Skip to main content
IBM Quantum Platform

QPY-Serialisierung

qiskit.qpy

QPY ist ein binäres Serialisierungsformat für QuantumCircuit objekte, das plattformübergreifend, Python versionsunabhängig und rückwärtskompatibel ist. QPY sollte verwendet werden, wenn Sie einen Mechanismus zum Speichern oder Kopieren zwischen Systemen benötigen QuantumCircuit der die vollständige Qiskit-Objektstruktur beibehält (mit Ausnahme von benutzerdefinierten Attributen, die außerhalb des Qiskit-Codes definiert wurden). Dies unterscheidet sich von anderen Serialisierungsformaten wie OpenQASM ( 2.0 oder 3.0 ), das ein anderes Abstraktionsmodell hat und zu einem Verlust von Informationen führen kann, die in der ursprünglichen Schaltung enthalten sind (oder nicht in der Lage ist, einige Aspekte der Qiskit-Objekte darzustellen), oder Python 's Pickle, das das Qiskit-Objekt genau beibehält, aber nur für eine einzige Qiskit-Version funktioniert (es ist auch potenziell unsicher ).


Basisverwendung

Die Verwendung von QPY ist so definiert, dass sie einfach ist und die Benutzer-API der Serialisierer in der Standardbibliothek von Python, pickle und json, widerspiegelt. Es gibt 2 benutzerorientierte Funktionen: qiskit.qpy.dump() und qiskit.qpy.load() die verwendet werden, um QPY-Daten in ein Datei-Objekt zu übertragen bzw. Schaltkreise aus QPY-Daten in ein Datei-Objekt zu laden. Zum Beispiel:

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]

Die Funktion qiskit.qpy.dump() können Sie auch mehrere Stromkreise in eine einzige QPY-Datei aufnehmen:

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

und das Laden dieser Datei führt zu einer Liste mit allen Schaltkreisen

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

API-Dokumentation

load

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

GitHub

Laden einer QPY-Binärdatei

Diese Funktion dient dazu, eine serialisierte QPY Qiskit-Programmdatei zu laden und QuantumCircuit objekte aus ihrem Inhalt. Zum Beispiel:

from qiskit import qpy

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

oder mit einer gzip-komprimierten Datei:

import gzip
from qiskit import qpy

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

die den Inhalt der Datei qpy liest und eine Liste von QuantumCircuit objekten aus der Datei zurückgibt.

Parameter

  • file_obj (BinaryIO) – Ein dateiähnliches Objekt, das die QPY-Binärdaten für einen Schaltkreis enthält.
  • metadata_deserializer (type[JSONDecoder] | None) – Eine optionale JSONDecoder-Klasse, die für das cls kwarg des internen json.load Aufrufs verwendet wird, mit dem die JSON-Nutzdaten desserialisiert werden, die für das .metadata Attribut aller Programme in der QPY-Datei verwendet werden. Wird dies nicht angegeben, werden die Schaltkreis-Metadaten mithilfe der stdlib-Funktion json.load() unter Verwendung der Standardklasse JSONDecoder als JSON geparst.
  • annotation.QPUSerializerannotation_factories (Mapping[str, Callable[[], annotation.QPYSerializer]] | None) – Zuordnung von Namensräumen zu Funktionen, die neue Instanzen von erstellen, zur Verwaltung des Ladens benutzerdefinierter Annotation Objekte.

Rückgabe

Die Liste der Qiskit-Programme, die in den QPY-Daten enthalten sind. Es wird immer eine Liste zurückgegeben, auch wenn nur 1 Programm in den QPY-Daten vorhanden ist.

Erhöht

  • QiskitError - wenn file_obj keine gültige QPY-Datei ist
  • TypeError - Wenn ein ungültiger Datentyp geladen wird.
  • MissingOptionalLibraryError – Wenn die symengine Engine-Bibliothek beim Laden einer QPY-Nutzlast der Versionen 10, 11 oder 12 nicht installiert ist, die die symbolische Kodierung von symengine verwendet und Instanzen enthält ParameterExpression .
  • QpyError - wenn ein bekannter, aber nicht unterstützter Datentyp geladen wird.

Rückgabetyp

list[ QPY_SUPPORTED_TYPES]

dump

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

GitHub

QPY-Binärdaten in eine Datei schreiben

Mit dieser Funktion können Sie einen Schaltkreis in einer Datei speichern, um ihn später zu verwenden oder zwischen Maschinen zu übertragen. Das QPY-Format ist rückwärtskompatibel und kann mit zukünftigen Versionen von Qiskit geladen werden.

Zum Beispiel:

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()

von hier aus können Sie die Qpy-Daten in eine Datei schreiben:

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

oder eine gzip-komprimierte Datei:

import gzip

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

Dadurch wird der mit qpy serialisierte Schaltkreis in der angegebenen Datei gespeichert.

Parameter

  • programs (list[QPY_SUPPORTED_TYPES] | QPY_SUPPORTED_TYPES) – QPY-unterstützte Objekte, die wie das Objekt in der angegebenen Datei gespeichert werden sollen. QPY unterstützt QuantumCircuit.

  • file_obj (BinaryIO) – Das dateiähnliche Objekt, in das die QPY-Daten geschrieben werden

  • metadata_serializer (type[JSONEncoder] | None) – Eine optionale JSONEncoder-Klasse, der das .metadata Attribut für jedes Programm in programs übergeben wird und die cls als kwarg beim Aufruf von json.dump ()` verwendet wird, um dieses Wörterbuch in JSON zu serialisieren.

  • use_symengine (bool) – Dieses Flag wird von den von dieser Funktion unterstützten QPY-Versionen nicht mehr verwendet und hat keine Auswirkung auf die generierte QPY-Nutzlast, es sei denn, es wird ein Feld in einem QPY v13 -Dateikopf gesetzt, das nicht verwendet wird.

  • version (int) –

    Die zu sendende Version des QPY-Formats. Standardmäßig wird das neueste unterstützte Format von QPY_VERSIONaus Kompatibilitätsgründen können Sie jedoch, wenn Sie die erzeugte QPY-Nutzlast mit einer älteren Version von Qiskit laden müssen, auch eine ältere Version des QPY-Formats bis hinunter zur minimal unterstützten Exportversion auswählen, die sich nur während einer Qiskit-Hauptversion ändern kann, um eine ältere Version des QPY-Formats zu erzeugen. Die aktuelle QPY-Version und die minimal kompatible Version können Sie mit qpy.QPY_VERSION und qpy.QPY_COMPATIBILITY_VERSION abrufen.

    Anmerkung

    Wird eine ältere Version von QPY angegeben, bleiben die Einschränkungen und möglichen Fehler, die sich aus dem QPY-Format dieser Version ergeben, bestehen. Dies sollte nur verwendet werden, wenn Kompatibilität mit dem Laden der Nutzlast mit einer älteren Version von Qiskit erforderlich ist.

  • annotation.QPUSerializerannotation_factories (Mapping[str, Callable[[], annotation.QPYSerializer]] | None) – Zuordnung von Namensräumen zu Funktionen, die neue Instanzen von erstellen, zur Verwaltung der Sicherung benutzerdefinierter Annotation Objekte. Der nachfolgende Aufruf von load() muss ähnliche Serialisierungsobjekte verwenden, die das benutzerdefinierte Ausgabeformat dieser Serialisierer verstehen.

Erhöht

  • TypeError - Wenn ein ungültiger Datentyp eingegeben wird.
  • ValueError - Wenn eine nicht unterstützte Versionsnummer für das Argument version übergeben wird.

get_qpy_version

qiskit.qpy.get_qpy_version(file_obj)

GitHub

Diese Funktion identifiziert die QPY-Version der Datei.

Diese Funktion liest den Header von file_obj und gibt die Version im QPY-Format zurück. Der Cursor von file_obj wird nicht weiterbewegt. Wenn Sie dies für ein späteres Lesen verwenden, z. B. zum Aufruf von load()aufrufen, können Sie file_obj direkt übergeben. Zum Beispiel:

from qiskit import qpy

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

Parameter

file_obj (BinaryIO) – Ein dateiähnliches Objekt, das die QPY-Binärdaten für einen Schaltkreis enthält.

Rückgabe

Die QPY-Version der angegebenen Datei.

Rückgabetyp

int

Diese Funktionen lösen eine eigene Unterklasse von QiskitError wenn sie bei der Serialisierung oder Deserialisierung auf Probleme stoßen.

QpyError

exception qiskit.qpy.QpyError(*message)

GitHub

Basen: QiskitError

Vom qpy-Modul ausgelöste Fehler.

Legen Sie die Fehlermeldung fest.

Wenn eine niedrigere als die maximale QPY-Zielversion für die Serialisierung eingestellt ist, das zu serialisierende Objekt aber Merkmale enthält, die nicht in diesem Format dargestellt werden können, wird eine Unterklasse von QpyError ausgelöst:

UnsupportedFeatureForVersion

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

GitHub

Basen: QpyError

QPY-Fehler, der ausgelöst wird, wenn die Ziel-Dump-Version zu niedrig für ein Merkmal ist, das in dem zu serialisierenden Objekt vorhanden ist.

Parameter

  • feature (str) – eine Beschreibung des problematischen Merkmals.
  • required (int) – die Mindestversion von QPY, die erforderlich wäre, um diese Funktion darzustellen.
  • target (int) – die Version von QPY, die für die Serialisierung verwendet wird.

qiskit.qpy.QPY_VERSION

Die aktuelle Version des QPY-Formats ab dieser Version. Dies ist der Standardwert für das Schlüsselwortargument version bei qpy.dump() und auch die Obergrenze für akzeptierte Werte für dasselbe Argument. Dies ist auch die Obergrenze für die Versionen, die von qpy.load().

Typ

int

qiskit.qpy.QPY_COMPATIBILITY_VERSION

Die aktuelle Mindestkompatibilitätsversion des QPY-Formats. Dies ist die Mindestversion, die qpy.dump() für das Schlüsselwortargument version akzeptieren wird. qpy.load() kann alle freigegebenen Formatversionen von QPY laden (bis QPY_VERSION).

Typ

int


QPY-Kompatibilität

Das QPY-Format ist so konzipiert, dass es auch in Zukunft rückwärtskompatibel ist. Das bedeutet, dass Sie in der Lage sein sollten, ein QPY mit einer neueren Qiskit-Version als derjenigen, die es erzeugt hat, zu laden. Das Laden einer QPY-Datei mit einer älteren Qiskit-Version wird jedoch nicht unterstützt und funktioniert möglicherweise nicht.

Wenn Sie zum Beispiel eine QPY-Datei mit qiskit-terra 0.18.1 erzeugt haben, können Sie diese QPY-Datei mit qiskit-terra 0.19.0 und einem hypothetischen qiskit-terra 0.29.0 laden. Das Laden dieser QPY-Datei mit 0.18.0 wird jedoch nicht unterstützt und funktioniert möglicherweise nicht.

Beachten Sie, dass Schaltkreis-Metadaten und benutzerdefinierte Annotation Objekte mithilfe von vom Benutzer bereitgestellten Klassen serialisiert und deserialisiert werden, da die Objekte selbst vollständig benutzerdefiniert sind. Daher ist die Vorwärts- und Rückwärtskompatibilität dieser Objekte auf das beschränkt, was der Benutzer bereitstellt.

Wenn eine Funktion, die geladen wird, in der entsprechenden qiskit-Version veraltet ist, löst QPY eine QPYLoadingDeprecatedFeatureWarning aus, das über den Zeitraum der Veralterung und die interne Behandlung der Funktion informiert.

QPYLoadingDeprecatedFeatureWarning

exception qiskit.qpy.QPYLoadingDeprecatedFeatureWarning

GitHub

Basen: QiskitWarning

Sichtbare Deprecation-Warnung für QPY-Funktionen, die ohne einen stabilen Punkt im Aufrufstapel geladen werden.

Anmerkung

Bei Qiskit-Versionen vor 1.2.4 konnte das use_symengine=True Argument zu qpy.dump() zu Problemen mit der Abwärtskompatibilität führen, wenn Objekte zu serialisieren waren ParameterExpression . Insbesondere gilt:

  • Wenn die Ladeversion von Qiskit 1.2.4 oder höher ist, können QPY-Dateien, die mit einer beliebigen Version von Qiskit >= 0.46.0 erzeugt wurden, geladen werden. Wenn eine Version von Qiskit zwischen 0.45.0 und 0.45.3 verwendet wurde, um die Dateien zu erzeugen, und das nicht standardmäßige Argument use_symengine=True an qpy.dump()angegeben wurde, kann die Datei nur gelesen werden, wenn die Version von symengine , die in der erzeugenden Umgebung verwendet wurde, zur Serie 0.11 oder 0.13 gehört. Wenn die Umgebung jedoch während des Support-Fensters von Qiskit 0.45 erstellt wurde, ist es wahrscheinlich, dass symengine==0.9.2 verwendet wurde.
  • Wenn die Ladeversion von Qiskit zwischen 0.46.0 und 1.2.2 liegt, kann die Datei nur gelesen werden, wenn die installierte Version von symengine in der Ladeumgebung mit der in der Erzeugungsumgebung verwendeten Version übereinstimmt.

Um eine QPY-Datei wiederherzustellen, die mit symengine versionsbezogenen Fehlern während eines Aufrufs von qpy.load()fehlschlägt, versuchen Sie zunächst, die Datei mit Qiskit >= 1.2.4 zu laden. Wenn dies immer noch fehlschlägt, liegt es wahrscheinlich daran, dass Qiskit 0.45.x verwendet wurde, um die Datei mit use_symengine=True zu erzeugen. Verwenden Sie in diesem Fall Qiskit 0.45.3 mit symengine==0.9.2 , um die Datei zu laden, und exportieren Sie sie anschließend mit use_symengine=False wieder nach QPY. Die resultierende Datei kann dann von jeder späteren Version von Qiskit geladen werden.

Anmerkung

Seit der Version 2.0.0 von Qiskit, mit der das Pulse-Modul aus der Bibliothek entfernt wurde, bietet QPY eine begrenzte Unterstützung für das Laden von Nutzdaten, die Pulsdaten enthalten. Laden einer ScheduleBlock Nutzlast, wird eine QpyError ausnahme ausgelöst werden. Wenn eine Nutzlast für eine Schaltung geladen wird, die Impulsgatter enthält, enthält die Ausgangsschaltung benutzerdefinierte Anweisungen ohne angehängte Kalibrierungsdaten für jedes Impulsgatter, wodurch sie undefiniert bleiben.

Versionshistorie des QPY-Formats

Wenn Sie vorhaben, eine QPY-Datei zwischen verschiedenen Qiskit-Versionen zu laden, ist es nützlich zu wissen, welche Versionen in einem bestimmten Release verfügbar waren. Da QPY rückwärts-, aber nicht vorwärtskompatibel ist, müssen Sie sicherstellen, dass eine bestimmte Version des QPY-Formats in der Version, die Sie aufrufen, freigegeben wurde load() mit. Die folgende Tabelle listet die QPY Versionen auf, die in jeder Qiskit (und qiskit-terra vor Qiskit 1.0.0 ) Version seit der Einführung von QPY in qiskit-terra 0.18.0 unterstützt wurden.

Qiskit (qiskit-terra für < 1.0.0 ) Version
dump() format(e) Ausgabeversionen
load() maximal unterstützte Version (ältere Formatversionen können immer gelesen werden)
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 (herausgerissen)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

QPY-Format

Das QPY-Serialisierungsformat ist ein portables, plattformübergreifendes binäres Serialisierungsformat für QuantumCircuit objekte in Qiskit. Das grundlegende Dateiformat ist wie folgt:

Eine QPY-Datei (oder ein Speicherobjekt) beginnt immer mit der folgenden 6-Byte-Zeichenkette UTF8 : QISKIT , unmittelbar gefolgt vom allgemeinen Dateikopf. Der Inhalt des Dateikopfes, der als C struct definiert ist, ist wie folgt:

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

Ab V10 wird der Datei-Header-Struktur ein neues Feld hinzugefügt, um das für symbolische Ausdrücke verwendete Kodierungsschema darzustellen:

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;
}

Ab V16 folgt auf die Datei-Header-Struktur unmittelbar eine Schaltkreis-Starttabelle mit den Byte-Offsets der einzelnen Schaltkreis-Nutzdaten in der Datei. Es gibt num_circuits Einträge in der Schaltkreis-Starttabelle, von denen jeder vom Typ uint64_t ist. In allen früheren Versionen folgen auf den Dateikopf unmittelbar die Nutzdaten der Schaltkreise, ohne dass dazwischen etwas aufgefüllt wird.

Alle Werte verwenden die Netzwerk-Byte-Reihenfolge [1] (Big-Endian) zur plattformübergreifenden Kompatibilität. Eine Ausnahme bildet das QPY-Format in den Versionen <= 17: Die Kodierung von Ganzzahlen und Gleitkommazahlen erfolgt dabei INSTRUCTION_PARAM im Little-Endian-Format.

Jeder einzelne Schaltkreis besteht aus den folgenden Teilen in der Reihenfolge von oben nach unten:

HEADER
METADATA
REGISTERS
ANNOTATION_HEADER
STANDALONE_VARS
CUSTOM_DEFINITIONS
INSTRUCTIONS

Geändert in Version QPY: 15 ANNOTATION_HEADER wurde zwischen REGISTERS und STANDALONE_VARS eingefügt.

Geändert in Version QPY: 12 STANDALONE_VARS wurde zwischen REGISTERS und CUSTOM_DEFINITIONS eingefügt.

Für jeden Schaltkreis gibt es eine Nutzlast (wobei die Gesamtzahl durch num_circuits im Dateikopf bestimmt wird). Zwischen den Schaltkreisen in den Daten gibt es keine Auffüllungen.

Version 17

Version 17 bietet nun Unterstützung für die Serialisierung und Deserialisierung PauliEvolutionGate von Objekten, die als Operator(en) enthalten SparseObservable sind.

Änderungen an PAULI_EVOLUTION

Das Format von PAULI_EVOLUTION selbst bleibt unverändert, jedoch wurde das Format der Operatoren, die unmittelbar auf das gepackte Evolutionsgatter folgen, aktualisiert. SparseObservableAnstelle von „operator_count“-Elementen, die im Format „SPARSE_PAULI_OP_LIST_ELEM“ definiert sind, gibt die Nutzlast nun den Typ jedes Operators an, um entweder Operatoren vom Typ SparsePauliOp oder vom Typ zu berücksichtigen.

Die neue Nutzlast nach PAULI_EVOLUTION enthält nun genau operator_count Sequenzen aus einem bool ("!?") gefolgt vom Operator. TrueIst der boolesche Wert, so ist der Operator ein SparseObservable und wird im neuen SPARSE_OBSERVABLE-Format interpretiert (siehe unten). FalseIst dies der Fall, handelt es sich bei dem Operator um ein SparsePauliOp und er wird gemäß dem bestehenden Format SPARSE_PAULI_OP_LIST_ELEM interpretiert.

Neu SPARSE_OBSERVABLE

SparseObservableDas Format SPARSE_OBSERVABLE stellt eine Instanz eines dar, die durch folgende Definition gegeben ist:

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;
}

unmittelbar gefolgt von der Anzahl der Qubits und dann den Datenarrays der Koeffizienten, Bit-Terme, Indizes und Grenzen der Observablen. Das Format gibt die Anzahl der Bytes an, die jedes Array belegt. Die Anzahl der Elemente kann berechnet werden, indem die Anzahl der Bytes durch die Größe jedes Elements geteilt wird.

  • Jeder Koeffizient wird als zwei aufeinanderfolgende „!d“-Elemente gespeichert, zuerst der Realteil und dann der Imaginärteil.
  • Die Elemente des Bit-Terms sind vom Typ „!„H“ und steht für den Wert „ u8 “ des SparseObservable.BitTerm
  • Die Indexelemente sind vom Typ „!Ich”.
  • Die Begrenzungselemente sind vom Typ „!Q”.

Version 16

Mit der Version 16 wurde das QPY-Dateiformat um eine Schaltkreis-Starttabelle erweitert. Er dient als Index für die Byte-Offsets der einzelnen Schaltkreis-Nutzdaten in der Datei. Die Motivation für diese Änderung ist, ein effizienteres Laden von Schaltkreisen mit Multi-Threading in einer zukünftigen Rust-Implementierung des QPY-Deserializers zu ermöglichen.

Änderungen an DURATION

Eine neue Variante wurde der bestehenden DURATION-Kodierung für Pikosekunden hinzugefügt. Diese ist wie folgt kodiert und kommt zu den bisher unterstützten Varianten hinzu.

Qiskit-Klasse
Typcode
Nutzdaten
pspEine double value.

Version 15

Mit Version 15 wird das Nutzdatenformat um das Konzept der benutzerdefinierten Anmerkungen erweitert. QPY selbst legt nicht fest, wie Anmerkungen serialisiert oder deserialisiert werden, da es sich um benutzerdefinierte Objekte handelt. Das Format arbeitet jedoch mit Subserialisierern zusammen.

Version 15 fügt das Feld ANNOTATION_HEADER zwischen den Feldern STANDALONE_VARS und CUSTOM_DEFINITIONS in der obersten Ebene der Nutzdaten einer einzelnen Schaltung ein. Es ändert die Interpretation eines Feldes der INSTRUCTION -Struktur in einer ABI-kompatiblen Weise und fügt einen INSTRUCTION_ANNOTATIONS -Trailer zu INSTRUCTION hinzu, der abhängig von einem gesetzten Bit in der INSTRUCTION -Nutzlast vorhanden ist.

Neue ANMERKUNG_KOPFZEILE

Das Feld ANNOTATION_HEADER ist eine Nutzlast variabler Größe im Header. Sie beginnt mit einer Instanz von ANNOTATION_HEADER_STATIC, der C-Struktur:

struct ANNOTATION_HEADER_STATIC {
    uint32_t num_namespaces;
}

Unmittelbar danach folgen die num_namespaces Instanzen der ANNOTATION_STATE Nutzlast. Die Reihenfolge ist wichtig und sollte während des Deserialisierungsprozesses beibehalten werden, da nachfolgende INSTRUCTION_ANNOTATION Payloads in diese indiziert werden.

Die Nutzlast von ANNOTATION_STATE beginnt mit der festen C-Struktur:

struct ANNOTATION_STATE_HEADER {
    uint32_t namespace_size;
    uint64_t state_size;
}

Unmittelbar nach diesem Header folgen namespace_size Bytes mit UTF-8 kodiertem Text, der den Namensraum enthält. Auf diese Bytes folgen unmittelbar state_size Bytes mit beliebigen Daten. Das Format dieser "Status"-Nutzlast ist von QPY nicht definiert. Stattdessen ist dafür ein externes Objekt verantwortlich, das mit dem gespeicherten Namensraum verbunden ist. Das Format schreibt nicht vor, wie diese Objekte zu erzeugen sind; da die Anmerkungen vollständig benutzerdefiniert sind, muss der Benutzer die Serialisierungs- und Deserialisierungsmethoden bereitstellen.

Änderungen an INSTRUCTION

Die INSTRUCTION struct wurde ABI-kompatibel zu ihrer früheren Definition in Version 9 geändert. Die neue Struktur ist die C-Struktur (erinnern Sie sich daran, dass zwischen den Feldern und am Ende der Struktur kein Padding vorhanden ist):

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;
}

wobei das Feld uint8_t extras_key das vorherige uint8_t conditional_key ersetzt. Der Unterschied besteht lediglich in der Auslegung. Die unteren zwei Bits des Bytes werden weiterhin als Definition der Bedingung und ihrer Art interpretiert. Das High-Bit des Bytes ist jetzt ein Flag, das anzeigt, ob ein INSTRUCTION_ANNOTATIONS_HEADER Feld in den nachfolgenden Daten der INSTRUCTION Struktur vorhanden ist (wenn das Bit gesetzt ist).

Eine vollständige Befehlsnutzlast erscheint im Datenstrom, einschließlich nachfolgender Objekte und ohne Auffüllungsbytes zwischen den Elementen, als:

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)

Es gelten die folgenden Hinweise:

  1. wenn die beiden niedrigen Bits von extras_key den Wert 2 haben, was bedeutet, dass die Bedingung EXPRESSION ist, ist conditional_reg_name_size immer Null.
  2. dieses Feld ist nur dann vorhanden, wenn die beiden niedrigen Bits von extras_key den Wert 2 haben, was bedeutet, dass die Bedingung EXPRESSION ist.
  3. dieses Feld ist nur dann vorhanden, wenn das High-Bit der extras_key gesetzt ist. Dieses Feld hat eine variable Größe; siehe Neue ANLEITUNG_ANMERKUNGEN.

Neue ANWEISUNGEN_ANMERKUNGEN

Die Nutzlast von INSTRUCTION_ANNOTATIONS beginnt mit der C-Struktur:

struct INSTRUCTION_ANNOTATIONS_HEADER {
    uint32_t num_annotations;
}

Unmittelbar danach folgen num_annotations Instanzen der INSTRUCTION_ANNOTATION Nutzlast, die eine variable Größe hat.

Die Nutzlast von INSRTUCTION_ANNOTATION ist definiert durch die folgende C-Struktur plus eine Anzahl von Bytes am Ende, die der payload_size entspricht, genannt ANNOTATION_PAYLOAD.

struct INSTRUCTION_ANNOTATION {
    uint32_t namespace_index;
    uint32_t payload_size;
}

namespace_index ist ein ganzzahliger Index in der Liste der definierten ANNOTATION_NAMESPACE Objekte in ANNOTATION_HEADER. Der Serialisierungsnamensraum für eine Anmerkung ist die UTF-8 kodierte Zeichenfolge in der entsprechenden Nutzlast.

Das Format des Objekts ANNOTATION_PAYLOAD ist von QPY nicht vorgegeben. Er wird durch ein externes Serialisierungsobjekt definiert, das mit dem Namespace, auf den der namespace_index verweist, und seinem zugehörigen Serialisierungsstatus im ANNOTATION_HEADER verbunden ist.

Änderungen innerhalb von „ PARAM_EXPR_ELEM_V13 “

Die Struktur selbst bleibt unverändert. Für ein PARAM_EXPR_ELEM_V13 , das einen ParameterExpression.subs() Aufruf darstellt (mit op_code = 15 und somit lhs_type = 'p' und rhs_type = 'n'), ordnet das nachgestellte MAPPING nun die Schlüssel der Rohbytes der Parameter UUIDs den ersetzten Werten zu. Bisher (in den QPY-Versionen 13 und 14) wurden bei dieser Zuordnung die Parameternamen als Schlüssel gespeichert.

Version 14

Version 14 enthält einen neuen Kerntyp DURATION, Unterstützung für zusätzliche Type klassen Float und Durationund einen neuen Ausdrucksknotentyp Stretch.

DAUER

Eine Duration wird durch einen Ein-Byte-ASCII-Code char kodiert, der die Art des Typs kodiert, gefolgt von einer Nutzlast, die je nach Typ variiert. Die definierten Codes sind:

Qiskit-Klasse
Typcode
Nutzdaten
dttEine unsigned long long value.
nsnEine double value.
usuEine double value.
msmEine double value.
ssEine double value.

Änderungen an EXPR_VAR_DECLARATION

Der Typ EXPR_VAR_DECLARATION wird nun verwendet, um sowohl Var eigenständige Variablen und Stretch bezeichner. Um diese Änderung zu unterstützen, hat der Verwendungsartencode zwei neue Eingabemöglichkeiten, zusätzlich zu den bereits vorhandenen:

Typcode
Bedeutung
AEine capture Strecke zum Rundkurs.
OEine örtlich festgelegte Strecke zum Rundkurs.

Änderungen an EXPRESSION

Der Code des Typs EXPRESSION hat einen neuen möglichen Eintrag, s, der den expr.Stretch knoten.

Qiskit-Klasse
Typcode
Nutzdaten
Kinder
StretchsEins unsigned short var_index0

Änderungen an EXPR_TYPE

Die folgende Tabelle zeigt die neuen Typklassen, die in dieser Version hinzugefügt wurden:

Qiskit-Klasse
Typcode
Nutzdaten
FloatfKeine.
DurationdKeine.

Änderungen an EXPR_VALUE

Das Typsystem des klassischen Ausdrucks unterstützt jetzt neue Kodierungstypen für Werteliterale, zusätzlich zu den bestehenden Kodierungen für int und bool. Die neuen Codierungen der Wertetypen sind unten aufgeführt:

Python typ
Typcode
Nutzdaten
floatfEine double value.
DurationtEine DURATION.

Version 13

In Version 13 wurde eine native Qiskit-Serialisierungsdarstellung für ParameterExpression. hinzugefügt. Frühere QPY-Versionen nutzten entweder sympy oder symengine zur Serialisierung des zugrunde liegenden symbolischen Ausdrucks. Ab Version 13 stellt QPY nun die Abfolge der API-Aufrufe dar, die zum Erstellen der ParameterExpression. verwendet werden.

Die wichtigste Änderung am Serialisierungsformat betrifft die Nutzdaten „PARAMETER_EXPR “. Die expr_size Bytes, die auf den Header folgen, enthalten nun ein Array von PARAM_EXPR_ELEM_V13 Strukturen. Dieses Array soll so ausgelegt sein, dass jeweils eine Struktur gelesen wird, wobei jede Struktur einen der Aufrufe beschreibt, die zur Rekonstruktion des ParameterExpression… erforderlich sind.

PARAM_EXPR_ELEM_V13

Das Format struct ist wie folgt definiert:

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

ParameterExpressionDas op_code Feld dient dazu, die Operation zu definieren, die zur hinzugefügt wird. Mögliche Werte:

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

Der Wert NULL von 255 wird nur verwendet, um das Op-Code-Feld für Einträge zu füllen, die keine eigentlichen Operationen sind, sondern rekursive Definitionen anzeigen. Dann werden die Felder lhs_type und rhs_type zur Beschreibung der Operandentypen verwendet und können eines der folgenden UTF-8 kodierten Zeichen sein:

Wert
Typ
nNone
pParameter
ffloat
ccomplex
iint
sBeginn der rekursiven ParameterExpression Definition
eRekursive ParameterExpression Definition – Ende
uErsetzung

i``fWenn der Typwert, c, oder ist, betragen die entsprechenden lhs Feldbreiten bzw. rhs jeweils 128 Bit. Bei Float-Werten wird der Literalwert als Double-Wert mit Auffüllung durch Nullen kodiert, während komplexe Zahlen als Realteil gefolgt vom Imaginärteil kodiert werden, wobei jeder Teil jeweils 64 Bit einnimmt. iDer Wert wird als vorzeichenbehaftete 64-Bit-Ganzzahl kodiert, wobei die gesamte 128-Bit-Breite mit Nullen aufgefüllt wird. n wird verwendet, um ein None darzustellen, und wird in der Regel nicht direkt verwendet, da es auf ein nicht verwendetes Argument hinweist. Denn p bei den Daten handelt es sich um die UUID für das Parameter , die in der Symbolzuordnung nachgeschlagen werden kann, die in der map_elements äußeren PARAMETER_EXPR -Nutzlast beschrieben ist. Wenn der Typwert lautet s , markiert dies den Beginn eines neuen rekursiven Abschnitts für ein verschachteltes ParameterExpression. final_exprIm folgenden Codeausschnitt gibt es beispielsweise ein inneres expr , das in enthalten ist und somit einen verschachtelten Ausdruck bildet:

from qiskit.circuit import Parameter

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

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

Wenn s auftritt, bedeutet dies, dass die Datenwerte bis zum Auftreten eines e` struct is reached, the next structs are used for a recursive definition. For both ``s und e Typs nicht verwendet und stets auf 0 gesetzt werden. Der Typwert von u wird verwendet, um einen Substitutionsaufruf darzustellen. nDies wird ausschließlich für lhs_type verwendet und wird immer mit einem rhs_type von kombiniert. Der Datenwert ist die Größe in Byte einer MAPPING -kodierten Zuordnung von Parameter Namen zu ihren Werten für den subs() Aufruf. Die Zuordnungsdaten folgen unmittelbar auf die Struktur, und die nächste Struktur beginnt unmittelbar nach den Zuordnungsdaten.

Version 12

Version 12 bietet Unterstützung für:

  • schaltungen, die speicherbehaftete expr.Var variablen enthalten.

Änderungen an HEADER

Die HEADER-Struktur für eine einzelne Schaltung hat drei uint32_t Zählungen der eingegebenen, erfassten und lokal deklarierten Variablen in der Schaltung hinzugefügt. Das neue Formular sieht wie folgt aus:

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;

Auf die HEADER_V12 struct folgt unmittelbar derselbe Name, dieselbe globale Phase, dieselben Metadaten und Registerinformationen wie bei der V2 Version des Headers. Unmittelbar nach den Registern folgt num_vars Instanzen von EXPR_VAR_STANDALONE , die die Variablen in dieser Schaltung definieren. Danach werden die Daten mit benutzerdefinierten Definitionen und Anweisungen wie in früheren Versionen von QPY fortgesetzt.

EXPR_VAR_DECLARATION

Eine EXPR_VAR_DECLARATION definiert eine expr.Var instanz, die eigenständig ist, d.h. sie repräsentiert eine eigene Speicherstelle und nicht eine Hülle aus Clbit oder ClassicalRegister. Die Nutzlast ist eine C-Struktur:

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

die unmittelbar von einer EXPR_TYPE Nutzlast und dann name_size Bytes von UTF-8 kodierenden Zeichenkettendaten gefolgt wird, die den Namen der Variablen enthalten.

Der char usage type code kann die folgenden Werte annehmen:

Typcode
Bedeutung
IEine input Variable für die Schaltung.
CEine capture Variable für die Schaltung.
LEine lokal deklarierte Variable in der Schaltung.

Änderungen an EXPR_VAR

Die Variable EXPR_VAR hat einen neuen Typcode und eine neue Nutzlast erhalten, zusätzlich zu den bereits vorhandenen:

Python klasse
Typcode
Nutzdaten
UUIDUEin uint32_t Index der Variablen in der Reihe der EXPR_VAR_STANDALONE Variablen, die unmittelbar nach dem Schaltkreiskopf geschrieben wurden.

Dieser neue Typcode indiziert vor allem vordefinierte Variablen aus dem Schaltkreiskopf, anstatt die Variable an jeder Stelle, an der sie verwendet wird, neu zu definieren.

Änderungen an EXPRESSION

Der Code des Typs EXPRESSION hat einen neuen möglichen Eintrag, i, der den expr.Index knoten.

Qiskit-Klasse
Typcode
Nutzdaten
Kinder
IndexiKeine zusätzliche Nutzlast. Die Kinder sind das Ziel und der Index, in dieser Reihenfolge.2

Version 11

Version 11 entspricht bis auf die folgenden Punkte der Version 10. UUID.hexErstens haben die Namen in den CUSTOM_INSTRUCTION-Blöcken ein Suffix der Form "_{uuid_hex}" , wobei uuid_hex eine UUID-Zeichenkette im Hexadezimalformat ist, wie sie beispielsweise von zurückgegeben wird. Beispiel: "b3ecab5b4d6a4eb6bc2b2dbf18d83e1e". Zweitens wird die Unterstützung für AnnotatedOperation Objekte hinzugefügt. ModifierDie Basisoperation einer annotierten Operation wird mithilfe des INSTRUCTION-Blocks gespeichert, und es wird ein zusätzlicher type Wert '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' hinzugefügt, um anzugeben, dass der Parameter vom Typ ist. Jeder Modifikator wird mithilfe der Struktur „MODIFIER“ gespeichert.

MODIFIER

Dies bedeutet Modifier

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

AnnotatedOperationDies reicht aus, um verschiedene Arten von Modifikatoren zu speichern, die für die Serialisierung von Objekten des Typs erforderlich sind. Das Feld type ist entweder 'i', 'c' oder 'p'und gibt an, ob es sich bei dem Modifikator jeweils um einen inversen Modifikator, einen Kontrollmodifikator oder einen Potenzmodifikator handelt. Im zweiten Fall legen die Felder num_ctrl_qubits und ctrl_state die Steuerlogik der Basisoperation fest, und im dritten Fall stellt das Feld power die Potenz der Basisoperation dar.

Version 10

Version 10 bietet Unterstützung für:

  • symengine-native Serialisierung für Objekte des Typs ParameterExpression sowie für symbolische Ausdrücke in Pulse-Zeitplanblöcken.
  • In der Qiskit-Version „ 0.45.0 “ wurden neue Felder zur TranspileLayout Klasse hinzugefügt.

Das Feld symbolic_encoding wird dem Dateikopf hinzugefügt, und es wird ein neuer Kodierungstyp char eingeführt, der den einzelnen symbolischen Bibliotheken wie folgt zugeordnet wird: p bezieht sich auf die Kodierung sympy und e auf die Kodierung symengine.

Änderungen an FILE_HEADER

Der Inhalt von FILE_HEADER nach V10 ist als C struct definiert als:

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;

Änderungen am LAYOUT

Die Struktur LAYOUT wird aktualisiert, um ein zusätzliches Feld input_qubit_count zu erhalten. Mit Version 10 ist die LAYOUT Struktur nun:

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;
}

Die übrigen Layout-Daten nach der LAYOUT struct werden wie in früheren Versionen dargestellt. NoneWenn input qubit_count < 0 ist, bedeutet dies, dass sowohl _input_qubit_count als auch _output_qubit_list im Objekt TranspileLayout sind.

VERSION 9

Version 9 bietet Unterstützung für klassische Expr knoten und ihre zugehörigen Types.

Ausdruck

Ein Expr knoten wird durch einen Datenstrom mit variabler Breite dargestellt. Ein Knoten selbst wird dargestellt durch (in der Reihenfolge des Bytestroms):

  1. einen Ein-Byte-Code-Diskriminator;
  2. ein EXPR_TYPE-Objekt;
  3. eine typcode-spezifische zusätzliche Nutzlast;
  4. eine typcode-spezifische Anzahl untergeordneter EXPRESSION-Payloads (die Anzahl dieser Payloads wird durch den Typcode impliziert und nicht explizit gespeichert).

Diese werden in der folgenden Tabelle beschrieben:

Qiskit-Klasse
Typcode
Nutzdaten
Kinder
VarxEine EXPR_VAR.0
ValuevEine EXPR_VALUE.0
CastcEine _Bool , die dem Wert von implicit entspricht.1
UnaryuEine uint8_t mit demselben numerischen Wert wie der Unary.Op.1
BinarybEine uint8_t mit demselben numerischen Wert wie der Binary.Op.2

EXPR_TYPE

A Type wird durch einen Ein-Byte-ASCII-Code char kodiert, der die Art des Typs verschlüsselt, gefolgt von einer Nutzlast, die je nach Typ variiert. Die definierten Codes sind:

Qiskit-Klasse
Typcode
Nutzdaten
BoolbKeine.
UintuEine uint32_t width.

EXPR_VAR

Dies stellt eine Laufzeitvariable eines Var knotens dar. Diese bestehen aus einem Typcode, gefolgt von einer typcodespezifischen Nutzlast:

Python klasse
Typcode
Nutzdaten
ClbitCEine uint32_t index , die den Index der Clbit in der enthaltenen Schaltung ist.
ClassicalRegisterREin uint16_t reg_name_size, gefolgt von so vielen Bytes an UTF-8 Stringdaten des Registernamens.

EXPR_VALUE

Dies stellt ein literales Objekt im klassischen Typsystem dar, z. B. eine ganze Zahl. Derzeit gibt es nur sehr wenige solcher Literale. Diese werden als Typcode kodiert, gefolgt von einer typcodespezifischen Nutzlast.

Python typ
Typcode
Nutzdaten
boolbEine _Bool value.
intiEine uint8_t num_bytes, gefolgt von der Ganzzahl, die in so vielen Bytes (Netzwerkreihenfolge) in Zweierkomplement-Darstellung kodiert ist.

Änderungen an INSTRUCTION

SwitchCaseOp.targetUm die Verwendung von Expr Knoten in den Feldern IfElseOp.condition, WhileLoopOp.condition und zu unterstützen, wird die Struktur „INSTRUCTION“ auf ABI-kompatible Weise an ihre vorherige Definition angepasst. Die neue Struktur ist die C-Struktur:

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;
}

wobei die einzige Änderung darin besteht, dass ein Eintrag uint8_t conditional_key an die Stelle von _Bool has_conditional getreten ist. Diese neue conditional_key nimmt die folgenden numerischen Werte an, mit diesen Auswirkungen:

Wert
Effekte
0Das Feld .condition der Anweisung ist auf None gesetzt. Die Felder conditional_reg_name_size und conditional_value sollten ignoriert werden.
1Das Feld .condition der Anweisung ist auf ein 2-Tupel aus entweder a Clbit oder a ClassicalRegisterund einer ganzen Zahl mit dem Wert conditional_value gesetzt. Die INSTRUCTION-Nutzdaten, einschließlich der Daten am Ende, werden genauso geparst wie in QPY-Versionen kleiner als 8.
2Das Feld .condition der Anweisung ist auf einen Expr knoten gesetzt. Die Felder conditional_reg_name_size und conditional_value sollten ignoriert werden. Auf die Daten nach dem struct folgen (wie in QPY-Versionen kleiner als 9) name_size Bytes von UTF-8 String-Daten für den Klassennamen und label_size Bytes von UTF-8 String-Daten für das Label (falls vorhanden). Dann gibt es einen INSTRUCTION_PARAM, der einen AUSDRUCK enthalten wird. Danach wird das Parsing mit den INSTRUCTION_ARG-Strukturen fortgesetzt, wie in früheren Versionen von QPY.

Änderungen an INSTRUCTION_PARAM

Es wurde ein neuer Typcode x hinzugefügt, der einen EXPRESSION-Parameter definiert.

Version 8

Version 8 bietet nun Unterstützung für die Verarbeitung eines TranspileLayout Werts, der im QuantumCircuit.layout Attribut gespeichert ist. In Version 8 befindet sich nun unmittelbar nach dem Kalibrierungsblock am Ende der Schaltungsnutzlast die LAYOUT Struktur. Diese Struktur gibt die Größe der drei Attribute einer TranspileLayout Klasse an.

Layout

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

Wenn einer der vorzeichenbehafteten Werte -1 ist, bedeutet dies, dass das entsprechende Attribut None ist.

Unmittelbar nach der LAYOUT struct folgt eine REGISTERS -Struktur für extra_registers (genauer gesagt das in Version 4 eingeführte Format) eigenständige Registerdefinitionen, die in der Schaltung nicht vorhanden sind. Außerdem gibt initial_layout_size es INITIAL_LAYOUT_BIT Strukturen zur Definition des TranspileLayout.initial_layout Attributs.

INITIAL_LAYOUT_BIT

struct {
    int32_t index;
    int32_t register_size;
}

Ein Wert von -1 bedeutet None (d. h. dem Bit ist kein Register zugeordnet). Nach jeder INITIAL_LAYOUT_BIT struct folgen register_size Bytes für eine utf8 kodierte Zeichenfolge für den Registernamen.

Nach dem anfänglichen Layout gibt es ein input_mapping_size Array mit uint32_t Ganzzahlen, die die Positionen der physischen Bits aus dem anfänglichen Layout darstellen. Auf diese Weise kann eine Liste virtueller Bits erstellt werden, bei der der Array-Index die Position der Eingangszuordnung ist.

Schließlich gibt es eine Reihe von final_layout_size uint32_t Ganzzahlen. Jedes Element ist ein Index im qubits -Attribut des Schaltkreises, der es ermöglicht, eine Zuordnung von der Ausgangsposition des Qubits zur Ausgangsposition am Ende des Schaltkreises zu erstellen.

Version 7

Version 7 bietet Unterstützung für Reference und die Serialisierung eines ScheduleBlock Programms unter Beibehaltung des Verweises auf Unterroutinen:

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)

Das herkömmliche SCHEDULE_BLOCK-Datenmodell wird beibehalten, aber in Version 7 folgt unmittelbar darauf ein zusätzlicher MAPPING utf8 Byte-Block, der die Daten der referenzierten Unterprogramme darstellt.

Die Gruppe SCHEDULE_BLOCK_INSTRUCTIONS für die Anweisung Reference wurde um ein neues Typschlüsselzeichen ergänzt.

  • y: Reference Anweisung

Der Gruppe SCHEDULE_BLOCK_OPERANDS wird ein neuer Typ Schlüsselzeichen für die Operanden der Anweisung Reference hinzugefügt, bei dem es sich um ein Tupel von Zeichenfolgen handelt, z. B. ( “cr45p”, “q0”, “q1” ).

  • ostring (Operandenstring)

Beachten Sie, dass dies die gleiche Kodierung ist wie bei der eingebauten Python string. Die Standardwertkodierung in QPY verwendet jedoch Zeichen des Typs s für Stringdaten, was mit dem SymbolicPulse im Bereich der Impulsbefehlsoperanden in Konflikt steht. Für die Zeichenketten, die in den Impulsbefehlsoperanden erscheinen, ist ein spezieller Zeichentyp o reserviert.

Darüber hinaus wurden in Version 7 zwei neue Typenschlüssel in die INSTRUCTION_PARM-Struktur aufgenommen. "d" wird von keinen Daten gefolgt und stellt den literalen Wert CASE_DEFAULT für die Unterstützung von Switch-Statements. "R" stellt eine ClassicalRegister oder Clbitund wird von demselben Format gefolgt wie die Beschreibung des Registers oder des klassischen Bits, das im ersten Element der Bedingung eines INSTRUCTION-Feldes verwendet wird.

Version 6

Version 6 bietet Unterstützung für ScalableSymbolicPulse. Diese Objekte werden wie SymbolicPulse Objekte gespeichert und gelesen, und der Klassenname wird zu den Daten hinzugefügt, um die Klassenauswahl korrekt zu behandeln.

SymbolicPulse block beginnt jetzt mit SYMBOLIC_PULSE_V2 header:

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;
}

Die einzige Änderung im Vergleich zu Version 5 ist die Hinzufügung der Klasse_name_size. Auf den Header folgt unmittelbar class_name_size utf8 Bytes mit dem Namen der Klasse. Derzeit werden entweder SymbolicPulse oder ScalableSymbolicPulse unterstützt. Der Rest der Daten ist dann identisch mit Version 5.

Version 5

Version 5 unterscheidet sich von Version 4 durch die Einführung der Unterstützung für ScheduleBlock sowie durch die Änderung von zwei Payloads: der INSTRUCTION-Metadaten-Payload und des CUSTOM_INSTRUCTION-Blocks. Diese verfügen nun über neue Felder, um Objekte in einem Schaltkreis besser zu ControlledGate erfassen. Zudem wird die neue Nutzlast MAP_ITEM definiert, um den MAPPING -Block zu implementieren.

Anmerkung

Die Unterstützung für die Darstellung von Impulsplänen und benutzerdefinierten Kalibrierungen wurde in Qiskit v2.0 entfernt. Beim Laden von QPY-Nutzdaten werden diese Datenfelder nun ignoriert oder lösen einen Fehler aus, wenn Qiskit für die Deserialisierung verwendet wird.

In QPY Version 5 und höher,

struct {
    char type;
}

folgt unmittelbar auf den Datei-Header-Block, um den in der Datei gespeicherten Programmtyp darzustellen.

  • Wenn type==c, QuantumCircuit folgt die Nutzlast
  • Wenn type==s, ScheduleBlock folgt die Nutzlast
Anmerkung

Verschiedene Programme können nicht in eine Datei gepackt werden. Sie müssen für die verschiedenen Programmtypen unterschiedliche Dateien erstellen. Mehrere Objekte desselben Typs können in einer einzigen Datei gespeichert werden.

ZEITPLAN_BLOCK

ScheduleBlock wird erstmals in QPY Version 5 unterstützt. Dies ermöglicht es dem Benutzer, Pulsprogramme im QPY-Binärformat wie folgt zu speichern:

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]

Beachten Sie, dass Schaltkreis und Zeitplanblock über dieselbe QPY-Schnittstelle serialisiert und deserialisiert werden. Der Eingangsdatentyp wird implizit analysiert, und es ist keine zusätzliche Option erforderlich, um den Zeitplanblock zu speichern.

SCHEDULE_BLOCK_HEADER

ScheduleBlock block beginnt mit der folgenden Kopfzeile:

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

unmittelbar gefolgt von name_size utf8 Bytes des Zeitplannamens und metadata_size utf8 Bytes des JSON serialisierten Metadatenwörterbuchs, das dem Zeitplan beigefügt ist.

ZEITPLAN_BLOCK_AUSRICHTUNGEN

Dann beginnt der Ausrichtungskontext des Zeitplanblocks mit char , das den unterstützten Kontexttyp angibt, gefolgt von dem SEQUENCE-Block, der die mit dem Ausrichtungskontext verbundenen Parameter darstellt AlignmentKind._context_params. Der Kontexttyp char wird wie folgt auf jede Ausrichtungsunterklasse abgebildet:

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

Beachten Sie, dass der Kontext AlignFunc aufgrund der in den Kontextparametern gespeicherten Callback-Funktion nicht unterstützt wird.

ZEITPLAN_BLOCK_ANWEISUNGEN

Auf diesen Ausrichtungsblock folgt num_element Länge der Blockelemente, die aus verschachtelten Zeitplanblöcken und Zeitplananweisungen bestehen können. Jeder Zeitplanbefehl beginnt mit char , das den Befehlstyp angibt, gefolgt von dem SEQUENCE-Block, der den Befehl operands darstellt. Beachten Sie, dass die Datenstruktur von pulse Instruction so vereinheitlicht ist, dass die Instanz eindeutig durch die Klasse und ein Tupel von Operanden bestimmt werden kann. Die Zuordnung des Typs char zur Befehlsunterklasse ist wie folgt definiert:

  • a: Acquire Anweisung
  • p: Play Anweisung
  • d: Delay Anweisung
  • f: SetFrequency Anweisung
  • g: ShiftFrequency Anweisung
  • q: SetPhase Anweisung
  • r: ShiftPhase Anweisung
  • b: RelativeBarrier Anweisung
  • t: TimeBlockade Anweisung
  • y Reference Befehl (neu in Version ) 0.7

SCHEDULE_BLOCK_OPERANDS

Die Operanden dieser Instanzen können über den Standard-QPY-Werteserialisierungsmechanismus serialisiert werden, es gibt jedoch spezielle Objekttypen, die nur in den Zeitplanoperanden vorkommen. Da die Operanden als SEQUENCE serialisiert werden, muss jedes Element mit der INSTRUCTION_PARAM pack struct gepackt werden, wobei jede Nutzlast mit einem Header-Block beginnt, der aus dem char type und uint64_t size besteht. Spezielle Objekte beginnen mit dem folgenden Typenschlüssel:

  • c: Channel
  • w: Waveform
  • s: SymbolicPulse
  • ostring (Operand String, neu in Version 0.7 )

CHANNEL

Der Kanalblock beginnt mit dem Kanalsubtyp char , der die Daten eines Objekts der Unterklasse Channel zuordnet. Das Mapping ist wie folgt definiert:

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

Auf die Taste folgt unmittelbar der Kanalindex, der als INSTRUCTION_PARAM serialisiert ist.

Wellenform

Der Wellenformblock beginnt mit dem WAVEFORM-Header:

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

gefolgt von data_size Bytes komplexer ndarray Binärdaten, die durch numpy.save. Dies stellt die komplexen IQ-Datenpunkte dar, die auf einem Quantengerät abgespielt werden. name wird nach den Samples in der INSTRUCTION_PARAM pack struct gespeichert, die ein String oder None sein kann.

SymbolicPulse

SymbolicPulse block beginnt mit dem SYMBOLIC_PULSE-Header:

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

gefolgt von type_size utf8 Bytes SymbolicPulse.pulse_type String, der eine Klasse von Wellenformen repräsentiert, wie z. B. "Gauß" oder “GaussianSquare”. Dann werden envelope_size, constraints_size, valid_amp_conditions_size utf8 Bytes mit serialisierten symbolischen Ausdrücken für SymbolicPulse.envelope, SymbolicPulse.constraints bzw. SymbolicPulse.valid_amp_conditions erzeugt. Da die String-Darstellung dieser Ausdrücke in der Regel sehr lang ist, wird der binäre Ausdruck vom Python-Zlib-Modul mit Datenkompression erzeugt.

Um eine Impulsinstanz eindeutig zu spezifizieren, müssen wir auch die zugehörigen Parameter speichern, die aus duration und dem Rest der Parameter als Wörterbuch bestehen. Die Dictionary-Parameter werden zunächst in der Form MAPPING und dann duration mit der Pack-Struktur INSTRUCTION_PARAM ausgegeben. Schließlich wird name auch mit der INSTRUCTION_PARAM pack struct gespeichert, die ein String oder None sein kann.

Zuordnung

Das MAPPING ist eine Darstellung für ein beliebiges Mapping-Objekt. Dies ist eine SEQUENCE fester Länge von Schlüssel-Wert-Paaren, die durch die MAP_ITEM-Nutzlast dargestellt werden.

Ein MAP_ITEM beginnt mit einer Kopfzeile, die wie folgt definiert ist:

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

unmittelbar darauf folgen die key_size utf8 Bytes, die den Wörterbuchschlüssel in Form einer Zeichenkette darstellen, und size utf8 Bytes mit beliebigen Objektdaten von QPY serializable type.

SCHALTKREIS_KALIBRIERUNGEN

Der Block CIRCUIT_CALIBRATIONS ist ein Wörterbuch zur Definition von Impulskalibrierungen des benutzerdefinierten Befehlssatzes. Dieser Block beginnt mit der folgenden Kopfzeile CALIBRATION:

struct {
    uint16_t num_cals;
}

gefolgt von der Länge num_cals der Kalibrierungseinträge, die jeweils mit der Kopfzeile CALIBRATION_DEF beginnen:

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

Auf den Kopf der Kalibrierungsdefinition folgen name_size utf8 Bytes des Gatternamens, num_qubits Länge der Ganzzahlen, die eine Folge von Qubits darstellen, und num_params Länge der INSTRUCTION_PARAM-Nutzlast für Parameter, die mit dem benutzerdefinierten Befehl verbunden sind. Das type gibt die Klasse des Impulsprogramms an, die entweder prinzipiell ScheduleBlock oder Schedule ist. Ab QPY Version 5 wird nur noch die Nutzlast ScheduleBlock unterstützt. Schließlich wird die SCHEDULE_BLOCK-Nutzlast für jeden CALIBRATION_DEF-Eintrag gepackt.

Anweisung

Der INSTRUCTION-Block wurde geändert, um zwei neue Felder num_ctrl_qubits und ctrl_state hinzuzufügen, die zur Modellierung der ControlledGate.num_ctrl_qubits Attribute und ControlledGate.ctrl_state dienen. Das neue Format der gepackten „payload“-Struktur lautet:

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;
}

Der Rest der Nutzlast des Befehls ist derselbe. Die Einzelheiten der vollständigen Nutzlast können Sie den ANLEITUNGEN entnehmen.

BENUTZERDEFINIERTE ANWEISUNG

Der Block „CUSTOM_INSTRUCTION“ in QPY Version 5 fügt ein neues Feld base_gate_size hinzu, das dazu dient, die Größe des qiskit.circuit.Instruction im ControlledGate.base_gate Attribut „“ gespeicherten Objekts für ein benutzerdefiniertes ControlledGate Objekt festzulegen. Mit dieser Änderung sieht der Metadatenblock CUSTOM_INSTRUCTION nun wie folgt aus:

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
}

Unmittelbar nach der CUSTOM_INSTRUCTION struct folgt der utf8 kodierte Name der Größe name_size.

Wenn custom_definition ist True , bedeutet dies, dass die unmittelbar darauf folgenden size Bytes QPY-Schaltungsdaten enthalten, die für die benutzerdefinierte Definition dieses Gatters verwendet werden können. Wenn custom_definition gilt False , dann kann die Anweisung als undurchsichtig betrachtet werden (d. h. keine Definition). Das type Feld legt fest, welche Art von Objekt mit der benutzerdefinierten Definition erstellt wird. Wenn es ist 'g' , handelt es sich um ein Gate Objekt; 'i' wenn es ist, handelt es sich um ein Instruction Objekt.

Danach enthalten die nächsten base_gate_size Bytes die INSTRUCTION Nutzlast für die ControlledGate.base_gate.

ControlledGateZudem wird ein Zusatzwert für type hinzugefügt 'c' , der angibt, dass es sich bei der benutzerdefinierten Anweisung um eine benutzerdefinierte handelt.

Version 4

Version 4 ist identisch mit Version 3, mit der Ausnahme, dass sie der INSTRUCTION_PARAM-Struktur zwei neue Zeichenketten hinzufügt: z zur Darstellung von None (die als keine Daten kodiert ist), q zur Darstellung einer QuantumCircuit (die als QPY-Schaltung kodiert ist), r für eine range von Ganzzahlen (die als RANGE kodiert ist) und t für eine sequence (die wie in SEQUENCE definiert kodiert ist). Darüber hinaus wurde in Version 4 der Typ des Registerindex-Mapping-Arrays von uint32_t auf int64_t geändert. Wenn die Werte eines der Array-Elemente negativ sind, stellen sie ein Registerbit dar, das in der Schaltung nicht vorhanden ist.

Das REGISTERS-Header-Format wurde ebenfalls aktualisiert, um

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

das lediglich das Feld in_circuit hinzufügt, das angibt, ob das Register Teil der Schaltung ist oder nicht.

BEREICH

Ein RANGE ist eine Darstellung eines range Objekts. Sie ist definiert als:

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

SEQUENCE

Eine SEQUENCE ist eine Darstellung eines beliebigen Sequenzobjekts. Da Sequenzen nur Container mit fester Länge für beliebige Python-Objekte sind, kann ihr QPY nicht jede Sequenz vollständig darstellen, aber solange der Inhalt einer Sequenz ein anderer in QPY serialisierbarer Typ für die INSTRUCTION_PARAM-Nutzlast ist, kann das "Sequenz"-Objekt serialisiert werden.

Ein Sequenzinstruktionsparameter beginnt mit einer Kopfzeile, die wie folgt definiert ist:

struct {
    uint64_t size;
}

gefolgt von size Elementen, die INSTRUCTION_PARAM-Payloads sind, wobei jedes dieser Elemente ein Element in der Sequenz definiert. Das Sequenzobjekt wird in den richtigen Typ umgewandelt, z.B. tuple, danach.

Version 3

Version 3 des QPY-Formats entspricht Version 2, mit der Ausnahme, dass sie ein Strukturformat definiert, um ein PauliEvolutionGate in QPY nativ darzustellen. Zu diesem Zweck unterstützt die Struktur CUSTOM_DEFINITIONS nun einen neuen Typ „value“ 'p' , der ein PauliEvolutionGate. darstellt. Einträgen in den Tabellen für benutzerdefinierte Anweisungen wird ein eindeutiger Name zugewiesen, der mit der Zeichenfolge "###PauliEvolutionGate_" beginnt, gefolgt von einer UUID-Zeichenfolge. Dieser Gate-Name ist in QPY reserviert. Wenn Sie ein benutzerdefiniertes Instruction Objekt mit einem Definitionssatz und diesem Namenspräfix haben, wird ein Fehler ausgegeben. Wenn es vom Typ 'p' ist, wird die Datenlast wie folgt definiert:

PAULI_EVOLUTION

Dies entspricht dem hohen Niveau PauliEvolutionGate

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

Darauf folgen operator_count unmittelbar Elemente, die durch die Nutzlast „SPARSE_PAULI_OP_LIST_ELEM“ definiert sind. Danach folgen time_size Bytes, die das time Attribut darstellen. Wenn standalone_op gilt True , dann darf es nur einen einzigen Operator geben. time_typeDie Kodierung dieser Bytes wird durch den Wert von bestimmt. Mögliche Werte für time_type sind 'f', 'p', und 'e'. ParameterWenn time_type ist 'f' , handelt es sich um ein Double; 'p' definiert ein Parameter Objekt, das durch einen PARAMETER dargestellt wird; e definiert ein ParameterExpression Objekt (das kein ist), das durch einen PARAMETER_EXPR dargestellt wird. Darauf folgen synthesis_size Bytes, bei denen es sich um eine nach dem „ utf8 “-Schema kodierte JSON-Nutzlast handelt, die die EvolutionSynthesis vom Gate verwendete Klasse darstellt.

SPARSE_PAULI_OP_LIST_ELEM

Dies ist ein Beispiel für SparsePauliOp.

struct {
    uint32_t pauli_op_size;
}

darauf folgen unmittelbar Bytes im pauli_op_size .npy-Format [2], die die Daten darstellen, die das SparsePauliOp.

ParameterIn Version 3 des QPY-Formats wird außerdem ein Strukturformat definiert, um ein ParameterVectorElement als eigenständige Unterklasse von einem darzustellen. Dadurch wird ein neuer Parametertyp „char“ 'v' hinzugefügt, der einen ParameterVectorElement Wert vom Typ „Zeichenkette“ darstellt, der nun als Wert für einen INSTRUCTION_PARAM unterstützt wird. Die Nutzdaten für diese Parameter sind im Folgenden als PARAMETER_VECTOR_ELEMENT definiert.

PARAMETER_VECTOR_ELEMENT

Ein PARAMETER_VECTOR_ELEMENT stellt ein ParameterVectorElement Objekt dar, das die Daten für einen INSTRUCTION_PARAM enthält. Der Inhalt von PARAMETER_VECTOR_ELEMENT ist wie folgt definiert:

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

unmittelbar gefolgt von vector_name_size utf8 Bytes, die den Namen des Vektors des Parameters darstellen.

PARAMETER_EXPR

Da zudem ab Version v3 des QPY-Formats zwischen a Parameter und ParameterVectorElement unterschieden wird, muss die Nutzlast für a ParameterExpression aktualisiert werden, um zwischen den Typen unterscheiden zu können. Im Folgenden wird das modifizierte Payload-Format beschrieben, das weitgehend mit dem Format in Version 1 und Version 2 identisch ist, lediglich die map_elements Struktur um ein Feld vom Typ „Symbol“ erweitert wurde.

Ein PARAMETER_EXPR steht für ein ParameterExpression Objekt, das die Daten für einen INSTRUCTION_PARAM enthält. Der Inhalt eines PARAMETER_EXPR ist wie folgt definiert:

struct {
    uint64_t map_elements;
    uint64_t expr_size;
}

Unmittelbar nach dem Header folgen expr_size Bytes von utf8 Daten, die die Ausdruckszeichenfolge enthalten, die die Sympy srepr des Ausdrucks für den Parameterausdruck ist. Es folgt eine Symbolkarte, die map_elements Elemente mit dem folgenden Format enthält

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

Der symbol_type Schlüssel bestimmt den Nutzlasttyp der symbolischen Darstellung des Elements. Wenn es ist p , steht es für ein Parameter und wenn es ist v , steht es für ein ParameterVectorElement. Auf die „map“-Element-Struktur folgt unmittelbar die Symbol-Map-Schlüssel-Nutzlast; wenn symbol_type ist p , folgt unmittelbar darauf ein PARAMETER -Objekt (sowohl die Struktur als auch die Namensbytes „ utf8 “), und wenn symbol_type ist v , folgt auf die Struktur unmittelbar ein PARAMETER_VECTOR_ELEMENT (sowohl die Struktur als auch die Namensbytes „ utf8 “). Darauf folgen size Bytes für die Daten des Symbols. Das Datenformat hängt vom Wert von type. ab. Wenn type ist p , dann stellt es ein Parameter dar und die Größe beträgt 0; der Wert entspricht dann einfach dem Schlüssel. Ebenso gilt: Wenn ist v``type , dann stellt es ein ParameterVectorElement dar, und die Größe beträgt 0, da der Wert einfach mit dem Schlüssel übereinstimmt. Wenn type ist f , dann handelt es sich um eine Gleitkommazahl mit doppelter Genauigkeit. Wenn type ist c , handelt es sich um eine komplexe Zahl mit doppelter Genauigkeit, die durch den Typ COMPLEX dargestellt wird. int64_tSchließlich stellt der Typ, falls er ist i , eine ganze Zahl dar, die ein ist.

Version 2

Version 2 des QPY-Formats ist identisch mit Version 1, nur der HEADER-Abschnitt ist etwas anders. Einzelheiten über das übrige Format der Nutzdaten finden Sie im Abschnitt Version 1.

KOPFZ.

Der Inhalt von HEADER ist als C struct definiert:

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;
}

Unmittelbar darauf folgen name_size Bytes mit Daten im Format „ utf8 “ für den Namen der Schaltung. Darauf folgen unmittelbar global_phase_size Bytes, die die globale Phase darstellen. global_phase_typeDer Inhalt dieser Daten wird durch den Wert von bestimmt. Wenn es sich 'f' um einen Float-Wert handelt und die Größe eines double… beträgt. ParameterWenn es 'p' ein Parameter Objekt definiert, das durch eine PARAM-Struktur dargestellt wird (siehe unten), e definiert es ein ParameterExpression Objekt (das kein ist), das durch eine PARAM_EXPR-Struktur dargestellt wird (siehe unten).

Version 1

KOPFZ.

Der Inhalt von HEADER, definiert als C struct, ist wie folgt:

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;
}

Unmittelbar danach folgen name_size Bytes mit utf8 Daten für den Namen des Stromkreises.

METADATA

Das METADATA-Feld ist eine UTF8 kodierte JSON-Zeichenfolge. Nach dem Lesen des HEADER (der eine feste Größe am Anfang der QPY-Datei hat) und der Zeichenfolge name lesen Sie die Anzahl der Bytes von metadata_size und analysieren das JSON, um die Metadaten für den Stromkreis zu erhalten.

Register

Der Inhalt von REGISTERS ist eine Nummer des REGISTER-Objekts. Wenn num_registers > 0 ist, liest man nach dem Lesen von METADATA die entsprechende Anzahl von REGISTER-Strukturen, die als definiert sind:

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

type kann 'q' oder 'c' sein.

Unmittelbar nach der REGISTER-Struktur folgt der utf8 kodierte Registername der Größe name_size. Nach den name utf8 Bytes folgt ein Array von int64_t Werten der Größe size , das eine Zuordnung zwischen dem Index des Registers und dem Qubit-Index der Schaltung enthält. Zum Beispiel ist das Array-Element 0’s der Index der Position von register[0]in der Liste der Qubits des enthaltenen Schaltkreises.

Anmerkung

Vor QPY Version 4 war der Typ der Array-Elemente uint32_t. Dies wurde geändert, um negative Werte zu ermöglichen, die Bits im Array darstellen, die in der Schaltung nicht vorhanden sind

Der Boolean standalone bestimmt, ob das Register als eigenständiges Register konstruiert wurde, das der Schaltung hinzugefügt wurde, oder ob es aus vorhandenen Bits erstellt wurde. Ein Register gilt als eigenständig, wenn es z. B. nur aus Bits besteht, die als Teil davon konstruiert wurden:

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

das Register qr wäre ein eigenständiges Register. Während etwas wie:

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

qr2 hätte standalone auf False gesetzt.

BENUTZERDEFINIERTE DEFINITIONEN

In diesem Abschnitt werden benutzerdefinierte Definitionen für alle Anweisungen in der Schaltung angegeben.

Der Inhalt von CUSTOM_DEFINITION_HEADER ist wie folgt definiert:

struct {
    uint64_t size;
}

Wenn die Größe größer als 0 ist, bedeutet dies, dass die Schaltung benutzerdefinierte Anweisungen enthält. Jede benutzerdefinierte Anweisung wird mit einem CUSTOM_INSTRUCTION-Block definiert, der wie folgt definiert ist:

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

Unmittelbar nach der CUSTOM_INSTRUCTION struct folgt der utf8 kodierte Name der Größe name_size.

Wenn custom_definition ist True , bedeutet dies, dass die unmittelbar darauf folgenden size Bytes QPY-Schaltungsdaten enthalten, die für die benutzerdefinierte Definition dieses Gatters verwendet werden können. Wenn custom_definition gilt False , dann kann die Anweisung als undurchsichtig betrachtet werden (d. h. keine Definition). Das type Feld legt fest, welche Art von Objekt mit der benutzerdefinierten Definition erstellt wird. Wenn es ist 'g' , handelt es sich um ein Gate Objekt; 'i' wenn es ist, handelt es sich um ein Instruction Objekt.

ANLEITUNGEN

Der Inhalt von INSTRUCTIONS ist eine Liste von INSTRUCTION-Metadatenobjekten

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;
}

Diesem Metadatenobjekt folgen unmittelbar name_size Bytes von utf8 Bytes für die name. name hier ist der Qiskit-Klassenname für die Klasse Instruction, wenn sie in Qiskit definiert ist. Andernfalls wird auf den benutzerdefinierten Befehlsnamen zurückgegriffen. Nach den name -Bytes folgen label_size -Bytes mit utf8 -Daten für die Kennzeichnung, falls eine solche im Befehl festgelegt wurde. Wenn has_conditional True ist, folgen nach den Kennzeichnungsbytes conditional_reg_name_size Bytes mit utf8 Daten für den Namen des bedingten Registers. Bei Bedingungen für ein einzelnes klassisches Bit wird dem Registernamen utf8 ein Null-Zeichen “x00” vorangestellt und dann eine ganze Zahl utf8, die den Index des klassischen Bits in dem Schaltkreis darstellt, auf den sich die Bedingung bezieht.

Unmittelbar danach folgen die INSTRUCTION_ARG-Strukturen für die Liste der Argumente der betreffenden Anweisung. Diese sind in der Reihenfolge aller Quantenargumente (von denen es num_qargs gibt), gefolgt von allen klassischen Argumenten (num_cargs von diesen).

Der Inhalt der einzelnen INSTRUCTION_ARG ist:

struct {
    char type;
    uint32_t index;
}

type kann 'q' oder 'c' sein.

Nach allen Argumenten für eine Anweisung werden die Parameter mit num_parameters INSTRUCTION_PARAM structs angegeben.

Der Inhalt der einzelnen INSTRUCTION_PARAMs ist:

struct {
    char type;
    uint64_t size;
}

Nach jedem INSTRUCTION_PARAM folgen die nächsten size Bytes, die die Daten des Parameters enthalten. 'i'Das type Feld kann, 'f', 'p', 'e', 's', 'c' oder 'n' sein, was das Format bestimmt. Wenn 'i' es sich um eine Ganzzahl handelt, 'f' ist es ein Double; 's' wenn es sich um eine Zeichenkette handelt (kodiert als utf8 ), 'c' ist es eine komplexe Zahl, und die Daten werden durch das Strukturformat im Abschnitt PARAMETER_EXPR dargestellt. Parameter'p' definiert ein Parameter Objekt, das durch eine PARAMETER -Struktur dargestellt wird; e definiert ein ParameterExpression Objekt (das kein ist), das durch eine PARAMETER_EXPR -Struktur dargestellt wird (im QPY-Format Version 3 ist das Format leicht angepasst, siehe: PARAMETER_EXPR ), 'n' stellt ein Objekt aus numpy dar (entweder ein ndarray oder einen numpy-Typ), was bedeutet, dass die Daten im.npy-Format [2] vorliegen, und in QPY Version 3 'v' stellt ein ParameterVectorElement dar, das durch eine PARAMETER_VECTOR_ELEMENT -Struktur repräsentiert wird.

PARAMETER

Ein PARAMETER stellt ein Parameter Objekt dar, das die Daten für einen INSTRUCTION_PARAM enthält. Der Inhalt des PARAMETERS ist wie folgt definiert:

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

unmittelbar gefolgt von name_size utf8 Bytes, die den Parameternamen darstellen.

PARAMETER_EXPR

Ein PARAMETER_EXPR steht für ein ParameterExpression Objekt, das die Daten für einen INSTRUCTION_PARAM enthält. Der Inhalt eines PARAMETER_EXPR ist wie folgt definiert:

Die PARAMETER_EXPR-Daten beginnen mit einer Kopfzeile:

struct {
    uint64_t map_elements;
    uint64_t expr_size;
}

Unmittelbar nach dem Header folgen expr_size Bytes von utf8 Daten, die die Ausdruckszeichenfolge enthalten, die die Sympy srepr des Ausdrucks für den Parameterausdruck ist. Es folgt eine Symbolkarte, die map_elements Elemente mit dem folgenden Format enthält

struct {
    char type;
    uint64_t size;
}

Darauf folgt unmittelbar das PARAMETER Objekt (sowohl die Struktur als auch die Namensbytes von „ utf8 “) für den Schlüssel der Symbolzuordnung. Darauf folgen size Bytes für die Daten des Symbols. Das Datenformat hängt vom Wert von type. ab. Wenn type ist p , dann stellt es ein Parameter dar und die Größe beträgt 0; der Wert entspricht dann einfach dem Schlüssel. Wenn type ist f , dann handelt es sich um eine Gleitkommazahl mit doppelter Genauigkeit. Wenn type ist c , stellt dies eine komplexe Zahl mit doppelter Genauigkeit dar, die durch COMPLEX repräsentiert wird. int64_tSchließlich stellt der Typ, falls er ist i , eine ganze Zahl dar, die ein ist.

KOMPLEX

Bei der Darstellung eines komplexen Wertes mit doppelter Genauigkeit in QPY wird die folgende Struktur verwendet:

struct {
    double real;
    double imag;
}

dies entspricht der internen C-Darstellung des komplexen Typs von Python. [3]


Referenzen

[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

War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.