Skip to main content
IBM Quantum Platform

Quanten-Schaltungsmodell

qiskit.circuit

Das grundlegende Element der Quanteninformatik ist der Quantenschaltkreis. Dabei handelt es sich um eine Berechnungsroutine, die auf einer Quantenverarbeitungseinheit (QPU) nacheinander ausgeführt werden kann. Ein Schaltkreis wirkt auf eine vordefinierte Menge von Quantendaten (in Qiskit unterstützen wir nur Qubits direkt) mit unitären Operationen (Gates), Messungen und Rücksetzungen. Darüber hinaus kann eine Quantenschaltung Operationen auf klassischen Daten enthalten, einschließlich Echtzeitberechnungen und Kontrollflusskonstrukte, die von den Controllern der QPU ausgeführt werden.

Schaltkreise befinden sich beim Aufbau von Quantenprogrammen auf einer niedrigen Abstraktionsebene. Sie sind das Konstrukt, das verwendet wird, um höhere Abstraktionsebenen zu erreichen, wie z. B. die Primitive der Quantenberechnung, die Daten aus vielen Schüssen der Ausführung von Quantenschaltungen zusammen mit fortgeschrittenen Fehlerminderungstechniken und Messoptimierungen zu gut typisierten klassischen Daten und Fehlerstatistiken akkumulieren.

In Qiskit können Schaltkreise in einem von zwei Regimen definiert werden:

  • eine abstrakte Schaltung, die durch virtuelle Qubits und beliebige Operationen auf hoher Ebene, wie gekapselte Algorithmen und benutzerdefinierte Gatter, definiert ist.
  • ein physikalischer Schaltkreis, der durch die Hardware-Qubits eines bestimmten Backends definiert ist und nur Operationen enthält, die dieses Backend von Haus aus unterstützt. Man kann dieses Konzept auch als ISA-Schaltung bezeichnen.

Sie konvertieren von einer abstrakten Schaltung in eine physische Schaltung, indem Sie das Transpilierpaket von Qiskit verwenden, dessen oberster Zugangspunkt ist transpile(). Wenn Sie einen Schaltkreis definieren, bei dem sich die Qubit-Indizes auf physikalische Qubits beziehen sollen, können Sie mit QuantumCircuit.ensure_physical() die Metadaten des Schaltkreises umschreiben, um sicherzustellen, dass Qiskit den Schaltkreis als physikalischen Schaltkreis erkennt. Im Gegensatz zur Transpilierung wird dadurch jedoch nicht erzwungen, dass die Basis-Gates und Hardware-Kopplungs-Bedingungen eingehalten werden.

In Qiskit wird ein Quantenschaltkreis durch die QuantumCircuit klasse dargestellt. Nachstehend ein Beispiel für einen Quantenschaltkreis, der einen Drei-Qubit-Zustand nach Greenberger-Horne-Zeilinger (GHZ) erzeugt:

∣ψ⟩=(∣000⟩+∣111⟩)/2|\psi\rangle = \left( |000\rangle + |111\rangle \right) / \sqrt{2}
from qiskit import QuantumCircuit

# Create a circuit with a register of three qubits
circ = QuantumCircuit(3)
# H gate on qubit 0, putting this qubit in a superposition of |0> + |1>.
circ.h(0)
# A CX (CNOT) gate on control qubit 0 and target qubit 1 generating a Bell state.
circ.cx(0, 1)
# CX (CNOT) gate on control qubit 0 and target qubit 2 resulting in a GHZ state.
circ.cx(0, 2)
# Draw the circuit
circ.draw('mpl')
Schaltplan, der durch den vorherigen Code ausgegeben wurde.

Schaltungskonzepte und Definitionen

Im Zusammenhang mit Quantenschaltungen gibt es eine Vielzahl von Fachbegriffen. Vieles davon ist in der Literatur zum Quantencomputing üblich, einiges ist spezifischer für Quantensoftwarepakete, und ein kleiner Teil ist spezifisch für Qiskit. Es handelt sich um eine alphabetische Auflistung einiger wichtiger Konzepte als Schnellreferenz, die jedoch nicht ins Detail der grundlegenden Konzepte geht. Wenn Sie ganz von vorne anfangen möchten, sollten Sie die Plattform IBM Quantum Learning nutzen.

abstrakter Schaltkreis

Ein Schaltkreis, der durch abstrakte mathematische Operationen und virtuelle Qubits definiert ist. So denkt man in der Regel über Quantenalgorithmen nach: Ein abstrakter Schaltkreis kann aus völlig beliebigen unitären Operationen, Messungen und potenziell klassischen Echtzeitberechnungen bestehen, ohne dass es Einschränkungen hinsichtlich der Qubits gibt, die miteinander interagieren können.

Sie verwandeln eine abstrakte Schaltung in eine physikalische Schaltung, indem Sie das Transpilationspaket von Qiskit verwenden.

hilfs-Qubit

Ein zusätzliches Qubit, das zur Durchführung von Operationen mit anderen Qubits verwendet wird, dessen Endzustand aber für das Programm nicht wichtig ist.

Verbindung

Eine Berechnungsroutine, die eine einzelne Ausführung auf einer QPU definiert. Dies kann entweder ein abstrakter Schaltkreis oder ein physischer Schaltkreis sein.

clbit

Eine Qiskit-spezifische Abkürzung, die ein einzelnes klassisches Datenbit bezeichnet.

Gatter

Eine unitäre Operation an einem oder mehreren Qubits.

hardware-Qubit

Die Darstellung eines einzelnen Qubits auf einer bestimmten QPU. Ein Hardware-Qubit verfügt über ein physikalisches quantenmechanisches System, z. B. supraleitende Schaltkreise; im Gegensatz zu einem virtuellen Qubit unterliegt es bestimmten Kopplungsbeschränkungen, und nur bestimmte Gatter können auf bestimmte Gruppen von Hardware-Qubits angewendet werden.

Qiskit unterscheidet nicht zwischen logischen Qubits und einzelnen physikalischen Qubits, wenn es um Hardware-Qubits geht. Eine QPU kann ihre Hardware-Qubits als logische Qubits implementieren, wobei jedes Hardware-Qubit viele physikalische Qubits umfasst, die von der Steuerelektronik kontrolliert und für Qiskit undurchsichtig fehlerkorrigiert werden. Wahrscheinlicher ist, dass eine QPU für kurzfristige Anwendungen ihre physikalischen Qubits direkt als Hardware-Qubits für Qiskit zur Verfügung stellen wird.

Sowohl physische als auch logische Qubits unterliegen Kopplungsbeschränkungen, lassen nur bestimmte Quantenoperationen zu und haben Probleme bei der Zeitplanung untereinander. Qiskit abstrahiert diese Belange in dem Konzept der Hardware-Qubits. In der Anfangsphase der Quantenfehlerkorrektur können bestimmte Backends den Zugriff auf ihre Qubit-Ressourcen entweder als logische Qubits auf hoher Ebene oder als physikalische Qubits auf niedriger Ebene über Qiskit ermöglichen.

befehlssatzarchitektur (ISA)

Das abstrakte Modell, das angibt, welche Operationen auf einer bestimmten QPU auf welchen Sätzen von Hardware-Qubits verfügbar sind. Eine QPU kann zum Beispiel X\sqrt X und RZR_Z Operationen auf allen einzelnen Hardware-Qubits und CXCX Operationen auf bestimmten Paaren von Hardware-Qubits erlauben.

logisches Qubit

Eine Sammlung mehrerer physikalischer Qubits, die gemeinsam von einer QPU (aus der Sicht des Nutzers) gesteuert werden, um Quantenfehlerkorrekturen in Echtzeit durchzuführen. Ein logisches Qubit ist eine Art von Hardware-Qubit für Qiskit.

Messung

Der Vorgang der Extraktion eines klassischen Bits einer Information aus einem einzelnen Qubit-Zustand. Dies ist ein irreversibler Vorgang, der in der Regel die Verschränkung und Phasenkohärenz zwischen dem Ziel-Qubit und dem Rest des Systems zerstört.

physische Verbindung

Eine Schaltung, die in Form von Hardware-Qubits und nur den Quantenoperationen definiert ist, die im ISA einer bestimmten QPU verfügbar sind. Physikalische Schaltungen sind an eine bestimmte QPU-Architektur gebunden und laufen nicht auf anderen inkompatiblen Architekturen. Man kann dies auch als ISA-Schaltung bezeichnen.

Eine physikalische Schaltung erhalten Sie in der Regel, indem Sie die Transpilationsroutinen von Qiskit auf eine von Ihnen konstruierte abstrakte Schaltung anwenden.

physikalisches Qubit

Ein kontrollierbares Zwei-Niveau-Quantensystem. Dies ist buchstäblich ein "physikalisches" Qubit, wie ein Transmon oder der elektronische Zustand eines gefangenen Ions. Eine QPU kann dies direkt als ihr Hardware-Qubit darstellen oder mehrere physische Qubits zu einem logischen Qubit kombinieren.

quantenverarbeitungseinheit (QPU)

Analog zu einer CPU im klassischen Computing oder einer GPU in der Grafikverarbeitung ist eine QPU die Hardware, die Quantenoperationen auf Quantendaten ausführt. Man kann immer davon ausgehen, dass eine QPU, die das Schaltkreismodell für Berechnungen verwendet, in der Lage ist, eine Reihe von Gattern und Messoperationen durchzuführen. Je nach Technologie können sie auch einige klassische Echtzeitberechnungen durchführen, wie z. B. den klassischen Kontrollfluss und bitweise Berechnungen mit klassischen Daten.

Qubit

Die Grundeinheit der Quanteninformation.

klassische Echtzeitberechnung

Jede klassische Berechnung, die während der Ausführung eines einzelnen Schusses einer Schaltung stattfinden kann, wobei die Ergebnisse der klassischen Berechnung die spätere Ausführung der Schaltung beeinflussen können. Der Umfang der klassischen Echtzeitberechnungen, die mit bestimmten QPUs zur Verfügung stehen, hängt von vielen Faktoren ab, z. B. von der Steuerelektronik und der verwendeten Qubit-Technologie. Weitere Informationen hierzu finden Sie in der Dokumentation Ihres Hardwareherstellers.

einheitliche Bedienung

Eine reversible Operation an einem Quantenzustand. Alle Quantengatter sind (per Definition) unitäre Operationen.

virtuelles Qubit

Ein abstraktes, mathematisches Qubit, das zum Aufbau eines abstrakten Schaltkreises verwendet wird. Wir gehen davon aus, dass alle Quantengatter auf allen virtuellen Qubits gültig sind und dass alle virtuellen Qubits immer mit jedem anderen virtuellen Qubit verbunden sind.

Bei der Abbildung auf Hardware müssen virtuelle Qubits den Hardware-Qubits zugeordnet werden. Diese Zuordnung muss nicht eins zu eins sein. Normalerweise muss ein virtuelles Qubit im Laufe der Ausführung eines Schaltkreises von einem Hardware-Qubit zu einem anderen ausgetauscht werden, um die Kopplungsbedingungen der zugrunde liegenden QPU zu erfüllen. Es ist nicht unbedingt erforderlich, dass alle virtuellen Qubits, die in einem Schaltkreis verwendet werden, zu einem beliebigen Zeitpunkt in einem physikalischen Schaltkreis auf ein physikalisches Qubit abgebildet werden; es könnte sein, dass ein virtuelles Qubit gemessen (sein Zustand kollabiert) und dann nie wieder verwendet wird, so dass ein neues virtuelles Qubit seinen Platz einnehmen könnte. Die Auswertung dieser Bedingungen, um eine virtuelle Schaltung auf eine physische Schaltung abzubilden, ist die Aufgabe des Transpilationspakets von Qiskit.


API-Übersicht von „ qiskit.circuit “

Alle hier aufgeführten Objekte werden in den folgenden Abschnitten ausführlicher und in ihrem größeren Zusammenhang beschrieben. Dieser Abschnitt gibt einen Überblick über die hier dokumentierten API-Elemente.

Die wichtigste Klasse ist QuantumCircuitdie eine eigene Dokumentationsseite hat, die auch einen ausführlichen Abschnitt über den Aufbau von Schaltkreisen enthält. Quantendaten und die einfachsten klassischen Daten werden durch "Bits" und "Register" dargestellt:

Innerhalb einer Schaltung besteht jede vollständige CircuitInstruction aus einem Operation (bei dem es sich um ein Instruction, ein Gate oder eine andere Unterklasse handeln kann) sowie den Operanden „Qubit“ und „Clbit“. Die wichtigsten Basisklassen sind hier:

Die häufigste konkrete Unterklasse der minimalen, abstrakten Operation Schnittstelle ist die Instruction. Während Operation abstrakte mathematische Objekte umfassen kann, ist ein Instruction etwas, das theoretisch direkt auf der Hardware ausgeführt werden könnte. Davon leiten sich wiederum die Unterklassen und ControlledGate ab Gate , die zusätzlich Unitarität und kontrollierte Semantik hinzufügen:

  • Instruction, was einen hardwarebasierten Befehl darstellt
  • Gate, was einen unitären Hardwarebefehl darstellt
  • ControlledGate, das ein Gatter mit einer Steuerungsstruktur darstellt.

Qiskit enthält eine große Bibliothek von Standardgattern und -schaltungen, die in qiskit.circuit.library. Viele von ihnen werden als Python -Objektsingletons deklariert. Die Maschinerie dafür ist im Detail beschrieben in qiskit.circuit.singletonbeschrieben, wobei die Hauptklassen jeweils eine Singleton-Form der Standard-Befehlsgatterhierarchie sind:

Einige Befehle sind insofern besonders, als sie den Kontrollfluss oder den Datenfluss der Schaltung beeinflussen. Die wichtigsten davon sind:

  • Barrier, um Teile der Schaltung zu markieren, die unabhängig voneinander optimiert werden sollen

  • Delayum eine Echtzeit-Wartezeit einzufügen

  • Measurezu messen Qubit in a Clbit

  • Resetum ein Qubit unwiderruflich in den Zustand ∣0⟩\lvert0\rangle zu versetzen

  • Storeum einen klassischen Echtzeit-Ausdruck in einen Speicherplatz zu schreiben

  • ControlFlowOp, das bestimmte Unterklassen aufweist:

    • BreakLoopOp, um aus der nächstgelegenen umschließenden Schleife auszubrechen
    • ContinueLoopOp, um sofort zur nächsten Iteration der übergeordneten Schleife überzugehen
    • BoxOp, eine einfache Gruppierung von Anweisungen
    • ForLoopOp, um einen festgelegten Wertebereich abzuklappern
    • IfElseOp, um bedingt in eine von zwei Teilschaltungen zu gelangen
    • SwitchCaseOp, um bedingt in eine von mehreren Teilschaltungen zu verzweigen
    • WhileLoopOp, um einen Teilablauf so lange zu wiederholen, bis eine Bedingung nicht mehr erfüllt ist.

Bestimmte Anweisungen können mit Metadaten „versehen“ werden, die in der Regel dazu bestimmt sind, von einem Compiler-Durchlauf entweder lokal oder bei der späteren Backend-Verarbeitung ausgewertet zu werden. Derzeit ist dies auf BoxOp. beschränkt. qiskit.circuit.annotationAnnotationDiese Annotationen werden durch benutzerdefinierte Unterklassen von dargestellt, und die unterstützende Infrastruktur wird in näher erläutert.

Schaltungen können klassische Ausdrücke enthalten, die in Echtzeit ausgewertet werden, während die QPU eine einzelne Aufnahme der Schaltung ausführt. Diese sind hauptsächlich in der Moduldokumentation von qiskit.circuit.classical. Sie könnten besonders an den Basisklassen interessiert sein (die nicht über den qiskit.circuit wurzel):

  • Varein typisierter klassischer Speicherplatz in einer Schaltung
  • Exprein in Echtzeit ausgewerteter Ausdruck
  • Type, der klassische Typ eines Ausdrucks.

Zusätzlich zu dieser Echtzeit-Ausdrucksevaluierung, die durch klassische Hardware-Repräsentationen von Daten begrenzt ist, verfügt Qiskit über das Konzept der "Kompilierzeit"-Parametrisierung, die in abstrakter symbolischer Algebra erfolgt. Diese werden typischerweise zur Darstellung von Gatterwinkeln in High-Level-Algorithmen verwendet, die numerische Ableitungen durchführen wollen, aber sie sind ein älterer Teil von Qiskit als die Echtzeitauswertung und werden daher noch an einigen Stellen zur allgemeinen Parametrisierung verwendet. Die wichtigsten verwandten Klassen sind:

Das qiskit.circuit modul stellt auch einige Berechnungsklassen zur Verfügung, die mit Schaltkreisen arbeiten, um Kompilierungsabläufe zu unterstützen. Diese umfassen:

Es gibt auch Dienstprogramme zur Erzeugung von Zufallsschaltungen:

Schließlich hat das Schaltkreismodul seine eigene Ausnahmeklasse, um anzuzeigen, wenn etwas auf schaltungsspezifische Weise schief gelaufen ist:


Darstellung von Schaltkreisen in Qiskit

Die wichtigste benutzerseitige Klasse zur Darstellung von Schaltkreisen ist QuantumCircuit. Dies kann entweder ein abstrakter Schaltkreis oder ein physischer Schaltkreis sein. Viele weitere Informationen über die Klasse QuantumCircuit klasse selbst und die Vielzahl der verfügbaren Methoden in ihrer Klassendokumentation.

Intern enthält ein QuantumCircuit die Qubits, klassische Bits, Parameter zur Kompilierungszeit, Echtzeitvariablen sowie weitere Nachverfolgungsinformationen zu den Daten, auf die es einwirkt, und zu seiner Parametrisierung. Es enthält dann eine Folge von CircuitInstructions, die jeweils die jeweilige Operation (Gatter, Messung usw.) und ihre Operanden (die Qubits und klassischen Bits) enthalten.

Bits und Register

Qubits und klassische Bits werden durch einen gemeinsamen Basistyp repräsentiert Bit typ repräsentiert, der nur als "Typ-Tag" gedacht ist; die Klassen haben kein anderes Verhalten, als unveränderliche Objekte zu sein:

Bit

class qiskit.circuit.Bit

GitHub

Basen: object

Implementieren Sie ein generisches Bit.

Anmerkung

Diese Klasse kann nicht direkt instanziiert werden. Sein einziger Zweck ist es, eine generische Typüberprüfung für Clbit und Qubit.

Qubit

class qiskit.circuit.Qubit(register=None, index=None)

GitHub

Basen: Bit

Ein Qubit, das zwischen verschiedenen Schaltkreisen verglichen werden kann.

Clbit

class qiskit.circuit.Clbit(register=None, index=None)

GitHub

Basen: Bit

Ein Clbit, der zwischen verschiedenen Schaltungen verglichen werden kann.

Qubits und clbits werden von Benutzern ohne Argumente instanziiert, z. B. durch Qubit(). Bits werden gleich verglichen, wenn es sich um dasselbe Python Objekt handelt, oder wenn sie beide durch ein Register mit demselben Namen und derselben Größe erstellt wurden und sich auf denselben Index innerhalb dieses Registers beziehen. Es gibt auch ein spezielles Typ-Tag für "Ancilla"-Qubits, das aber im gegenwärtigen Zustand von Qiskit wenig genutzt wird:

AncillaQubit

class qiskit.circuit.AncillaQubit

GitHub

Basen: Qubit

Ein Qubit, das als Hilfsmittel verwendet wird.

Eine Sammlung von Bits desselben Typs kann in einem Register des entsprechenden Typs gekapselt werden. Die Basisfunktionalität befindet sich in einer Basisklasse, die nicht direkt instanziiert wird:

Registrieren

class qiskit.circuit.Register

GitHub

Basen: object

Implementieren Sie ein allgemeines Register.

Anmerkung

Diese Klasse kann nicht direkt instanziiert werden. Sein einziger Zweck ist es, eine generische Typüberprüfung für ClassicalRegister und QuantumRegister.

Jeder der definierten Bit-Subtypen hat ein zugehöriges Register, das die gleichen Konstruktorsignaturen, Methoden und Eigenschaften wie die Basisklasse hat:

QuantumRegister

class qiskit.circuit.QuantumRegister(size=None, name=None, bits=None)

GitHub

Basen: Register

Implementieren Sie ein Register.

ClassicalRegister

class qiskit.circuit.ClassicalRegister(size=None, name=None, bits=None)

GitHub

Basen: Register

Implementieren Sie ein Register.

AncillaRegister

class qiskit.circuit.AncillaRegister(size=None, name=None, bits=None)

GitHub

Basen: QuantumRegister

Einführung eines Ancilla-Registers.

Eine gängige Methode, mehrere Bits auf einmal zu instanziieren, ist die Erstellung eines Registers, z. B. durch QuantumRegister("my_qreg", 5). Dies hat den Vorteil, dass Sie dieser Sammlung von Bits einen Namen geben können, der bei Schaltkreisvisualisierungen (QuantumCircuit.draw()) und bei Exporten in Austauschsprachen (siehe qasm2 und qasm3). Sie können auch einen Namen und eine Liste von vorkonstruierten Bits übergeben, aber dies erzeugt ein "Aliasing-Register", das von der Hardware nur sehr schlecht unterstützt wird.

Die Schaltungen verfolgen die Register, aber die Register selbst bewirken fast keine Verhaltensunterschiede bei den Schaltungen. Die einzige Ausnahme ist, dass ClassicalRegisters implizit in vorzeichenlose Ganzzahlen umgewandelt werden können, um in bedingten Vergleichen von Kontrollflussoperationen verwendet zu werden.

Klassische Register und Bits waren die ursprüngliche Art der Darstellung klassischer Daten in Qiskit und werden auch heute noch am meisten unterstützt. Längerfristig bewegt sich das Datenmodell auf eine vollständigere und stark typisierte Darstellung einer Reihe von klassischen Daten zu (siehe Klassische Echtzeitberechnung ), aber Sie werden in Qiskit immer noch sehr häufig klassische Bits verwenden.

Unterrichtskontexte

Der Skalar-Typ der QuantumCircuit.data Sequenz ist das Objekt „Befehlskontext“, CircuitInstruction. Im Grunde handelt es sich hierbei lediglich um eine Datenklasse, die eine Darstellung dessen enthält, was zu tun ist (ihr operation), sowie die Daten, auf die sie einwirkt (das qubits und clbitsdas ).

Kolumne „ 1 “
Kolumne „ 2 “
CircuitInstruction(Operation[, Qubits, Clbits] )Eine einzelne Anweisung in einer QuantumCircuit, bestehend aus der operation und verschiedenen Operanden.

Programmiertechnisch gesehen ist diese Klasse tatsächlich in Rust implementiert und stellt einen konstruierten Zugriff auf interne Daten innerhalb des Rust-Speicherbereichs dar. Änderungen an Instanzen dieser Klasse werden im Schaltkreis nicht berücksichtigt. Im Allgemeinen können Sie Befehlskontexte, die sich bereits in der Schaltung befinden, nicht direkt ändern; die QuantumCircuit Schnittstelle ist für das Speichern und Erstellen von Schaltungen konzipiert, während der Transpiler und seine Durchläufe sowie seine Zwischendarstellung DAGCircuit die Stellen sind, an denen Sie nach einer Schnittstelle zum Ändern von Schaltungen suchen sollten.

CircuitInstructionInstructionSetDie QuantumCircuit Methoden, die Schaltungen Anweisungen hinzufügen (wie z. B. append() sowie alle Hilfsmethoden für Standardgatter), geben ein zurück, das gleichzeitig als Handle für mehrere dient.

Kolumne „ 1 “
Kolumne „ 2 “
InstructionSet(*[, resource_requester] )Unterrichtssammlung und ihre Zusammenhänge.

Dies InstructionSet wird in Qiskit mittlerweile kaum noch verwendet. Es bietet eine sehr begrenzte Auswahl an Methoden, um nachträgliche Änderungen an Befehlen vorzunehmen (die an die Schaltung weitergegeben werden ), doch von deren Verwendung wird mittlerweile abgeraten; stattdessen sollten Sie die in diesen Methoden angegebenen Alternativen nutzen.

Operationen, Anweisungen und Tore

CircuitInstructionInnerhalb eines ist die minimale Schnittstelle, die jeder Vorgang erfüllen muss, Operation. Dies ist eine sehr allgemeine Darstellung, die nur für abstrakte Schaltungen verwendet werden kann. Der Hauptzweck der Behandlung von Operationen als Operation besteht darin, beliebige mathematische Objekte (wie beispielsweise quantum_info.Operator) direkt in abstrakte Schaltkreise einzufügen.

Kolumne „ 1 “
Kolumne „ 2 “
Operation()Quantum Operation Interface.

Die meisten Operationen, einschließlich aller Operationen auf physikalischen Schaltkreisen, sind Fälle der konkreter definierten Instruction. Dies bezeichnet jeden Befehl, den eine QPU möglicherweise nativ ausführen kann, wie zum Beispiel Measure. GateInstruction muss nicht unitär sein (so wie Measure es auch nicht ist); eine Anweisung ist genau dann unitär, wenn sie eine ist.

Kolumne „ 1 “
Kolumne „ 2 “
Instruction(name, num_qubits, num_clbits, params)Allgemeine Quanteninstruktion.

paramsInstructions können nahezu beliebig sein, vorausgesetzt, sie wirken nur auf Qubits und Clbits ein und werden durch ihre parametrisiert; sie sollten nicht versuchen, äußere Schaltungsregister zu „überdecken“, oder versteckte Parameter in ihrem Inneren zu verwenden. Instructions können mit anderen Schaltkreisen verknüpft werden, um mithilfe ihres Instruction.definition Attributs eine Zerlegung zu liefern, die eine lokale, einmalige Zerlegung ermöglicht. Dies kann in jedem beliebigen Operationsbasissatz erfolgen, der für Sie am zweckmäßigsten ist, solange die Definitionen aller enthaltenen Gatter eine topologische Ordnung aufweisen; das heißt, Sie dürfen ein Gatter nicht in einer Definition verwenden, wenn dessen eigene Definition vom übergeordneten Gatter abhängt. NoneWenn das Instruction für Optimierer als völlig undurchsichtig betrachtet werden soll, kann sein definition sein. Weitere Informationen finden Sie unter „Benutzerdefinierte Anweisungen erstellen “.

Die params einer Anweisung kann technisch gesehen beliebig sein, aber im Allgemeinen sollten Sie versuchen, sich nach Möglichkeit an Parametrisierungen in Form von reellen Zahlen zu halten. Qiskit selbst verstößt an vielen Stellen gegen diese Regel, und man findet in Instruction.params den Feldern alle möglichen ungewöhnlichen Typen, doch diese sind eine lästige Fehlerquelle, da sie oft die Notwendigkeit typabhängiger Sonderfälle mit sich bringen. Wenn Ihre Anweisung anhand von Winkeln parametrisiert ist, können Sie darin zuverlässig die Parametrisierung zur Kompilierungszeit nutzen, und sie lässt sich gut in QuantumCircuit.assign_parameters()… integrieren.

InstructionObwohl Instruction nicht unbedingt unitär ist, impliziert seine Unterklasse Gate die Unitarität und erweitert to_matrix() alle von geerbten Methoden um die Methoden und control() .

Kolumne „ 1 “
Kolumne „ 2 “
Gate(Name, Anzahl_Qubits, Parameter[, Bezeichnung] )Einheitliches Tor.

Gate erbt alle Methoden für Instruction sowie alle entsprechenden Überlegungen zu seinem params und definition Feld, abgesehen natürlich davon, dass Gates auf keine klassischen Ressourcen einwirken kann.

EquivalenceLibrarydefinitionGate Instanzen können (und sollten) eine Basis haben, aber man kann auch mehrere verschiedene Zerlegungen in unterschiedlichen Basen angeben, indem man ein verwendet.

GateWas die Erstellung von Unterklassen betrifft, verfügt Qiskit ebenfalls über eine spezielle ControlledGate Klasse. Diese Klasse bildet die Grundlage für viele Gatter der Standardbibliothek, die gesteuert werden (wie z. B. CXGate), und dort werden Sie ihr höchstwahrscheinlich begegnen:

Kolumne „ 1 “
Kolumne „ 2 “
ControlledGate(name, num_qubits, params[,...] )Kontrolliertes einheitliches Tor.

qiskit.circuit.singletonJedes der Elemente Instruction, Gate und ControlledGate verfügt über einen entsprechenden Singleton-Typ, der mithilfe der in beschriebenen Methode erstellt wurde. Die Dokumentation auf Modulebene enthält alle Einzelheiten sowie Beschreibungen zu SingletonInstruction, SingletonGate und SingletonControlledGate. base_classAus Sicht des Benutzers ändert sich kaum etwas, je nachdem, ob die Basisklasse ein Singleton ist oder nicht; es gilt stets die Regel, dass Sie zunächst aufrufen to_mutable() sollten, wenn Sie eine sicher veränderbare Kopie einer Anweisung benötigen (Sie können nicht davon ausgehen, dass eine beliebige Anweisung veränderbar ist), und obwohl von type einer direkten Überprüfung abgeraten wird, ist die zuverlässige Methode, den „Basis“-Typ einer potenziell als Singleton definierten Anweisung zu ermitteln, die Verwendung von, falls Sie dies doch benötigen.

ControlledGate nutzt dieselben Mechanismen wie die Unterklassenbildung von Gates, um eine feste, verzögerte Synthese für sich selbst zu definieren. Dies berücksichtigt natürlich nicht die Hardware und lässt sich schwerer in die Synthese-Routinen des Compilers integrieren, funktioniert aber besser als konkrete Instruction Lösung, die potenziell nativ auf der Hardware ausgeführt werden könnte. base_opFür Fälle, in denen die Synthese und die abstrakte Optimierung eine größere Rolle spielen, bietet Qiskit eine kombinierbare Klasse namens AnnotatedOperationan, die „Gate-Modifikatoren“ (zu denen ControlModifier auch gehört) verfolgt, um diese auf das innere anzuwenden.

Kolumne „ 1 “
Kolumne „ 2 “
AnnotatedOperation(Basis_Op, Modifikatoren)Kommentierte Operation.

Die verfügbaren Modifikatoren für AnnotatedOperation sind:

InverseModifier

class qiskit.circuit.InverseModifier

GitHub

Basen: Modifier

Inverser Modifikator: gibt an, dass die Operation invertiert wird.

ControlModifier

class qiskit.circuit.ControlModifier(num_ctrl_qubits=0, ctrl_state=None)

GitHub

Basen: Modifier

Steuerungsmodifikator: gibt an, dass der Vorgang von num_ctrl_qubits gesteuert wird und den Steuerungsstatus ctrl_state hat.

Parameter

  • num_ctrl_qubits (int)
  • ctrl_state (int |str | None)

PowerModifier

class qiskit.circuit.PowerModifier(power)

GitHub

Basen: Modifier

Potenzmodifikator: gibt an, dass der Vorgang auf die Potenz power angehoben wird.

Parameter

power (float)

Informationen zur Erstellung von benutzerdefinierten Gattern und Anweisungen, einschließlich der Erstellung von einmaligen Objekten und wiederverwendbaren parametrischen Gattern über Subclassing, finden Sie weiter unten unter Erstellen von benutzerdefinierten Anweisungen. Die Qiskit-Schaltungsbibliothek in qiskit.circuit.library enthält viele vordefinierte Gatter und Schaltungen, die Sie verwenden können.

Integrierte Sonderanweisungen

Qiskit enthält einige Instruction Klassen, die in gewisser Weise „besonders“ sind. Diese werden in der Regel im Schaltkreiscode, im Transpiler oder in den Hardware-Modellen besonders behandelt. Das sind alles Anweisungen, die Ihnen wahrscheinlich bereits bekannt sind.

Die Messungen in Qiskit werden von einem einzelnen Qubit in eine einzelne Clbit. Das sind die beiden, auf die die Anweisung angewendet wird. Die Messungen sind in der Berechnungsgrundlage enthalten.

Maß

class qiskit.circuit.Measure(label=None)

GitHub

Basen: SingletonInstruction

Quantenmessung in der Berechnungsgrundlage.

Parameter

label - optionale Stringbezeichnung für diese Anweisung.

Im Zusammenhang mit Messungen gibt es eine Reset operation, die keine klassischen Daten erzeugt, sondern die Hardware anweist, das Qubit in den Zustand ∣0⟩\lvert0\rangle zu versetzen. Es wird davon ausgegangen, dass dies inkohärent geschieht und jegliche Verschränkung kollabiert.

Zurückgesetzt

class qiskit.circuit.Reset(label=None)

GitHub

Basen: SingletonInstruction

Inkohärentes Zurücksetzen eines Qubits in den Zustand ∣0⟩\lvert0\rangle.

Parameter

label - optionale Stringbezeichnung dieser Anweisung.

Die Hardware kann so angesteuert werden, dass sie für ein bestimmtes Qubit eine Echtzeit-Ruhephase auslöst. Ein planmäßiger Schaltkreis (siehe qiskit.transpiler) berücksichtigt alle Leerlaufzeiten der Qubits explizit im Sinne dieses Delay. BoxOp kann zudem eine explizite Dauer enthalten, und zwar in seinem BoxOp.duration Feld.

Verzögerung

class qiskit.circuit.Delay(duration, unit=None)

GitHub

Basen: Instruction

Nichts tun und nur für eine bestimmte Dauer verzögern/abwarten/leeren.

Parameter

  • dauer - die Zeitdauer der Dauer. Wenn es sich um einen Exprist, muss es sich um einen konstanten Ausdruck vom Typ Duration sein und der Parameter unit sollte weggelassen werden (oder MUSS "expr" sein, wenn er angegeben ist).
  • unit - die Einheit der Dauer, wenn duration ein numerischer Wert ist. Muss "dt", eine SI-Sekundeneinheit mit Präfix oder "expr" sein.

Erhöht

CircuitError - Ein duration Ausdruck wurde mit einem aufgelösten Typ angegeben, der nicht zeitbasiert ist, oder unit wurde nicht korrekt angegeben.

Verzögerungsdauern können entweder mit konkreten, konstanten Zeiten oder mit "Dauerausdrücken" mit verzögerter Auflösung angegeben werden, die aus expr.Stretch objekten. Weitere Informationen hierzu finden Sie unter Terminierung mit verzögerter Auflösung.

Die Anweisung Barrier anweisung kann sich über eine beliebige Anzahl von Qubits und Clbits erstrecken und ist in der Hardware ein No-op. Während der Transpilierung und Optimierung blockiert sie jedoch jegliche Optimierungen, die die Barriere "überschreiten", d. h. in:

from qiskit.circuit import QuantumCircuit

qc = QuantumCircuit(1)
qc.x(0)
qc.barrier()
qc.x(0)

ist es dem Optimierer untersagt, die beiden Anweisungen XX aufzuheben.

Hindernis

class qiskit.circuit.Barrier(num_qubits, label=None)

GitHub

Basen: Instruction

Eine Richtlinie für die Kompilierung von Schaltkreisen, um Teile eines Schaltkreises zu trennen, so dass Optimierungen oder Umschreibungen nur zwischen den Barrieren stattfinden können.

Dies wird auch in Visualisierungen als visuelle Markierung erscheinen.

Parameter

  • num_qubits (int) – die Anzahl der Qubits für die Schranke.
  • label (str | None) – die optionale Bezeichnung dieser Barriere.

Die Anweisung Store anweisung ist insofern besonders, als sie das Schreiben des Ergebnisses eines klassischen Echtzeit-Rechenausdrucks (an expr.Expr) in eine lokale klassische Variable (a expr.Var). Es braucht weder Qubit noch Clbit operanden, sondern hat ein explizites lvalue und rvalue.

Um zum Beispiel die Parität einer Bitfolge cr zu bestimmen und in einem anderen Register creg zu speichern, kann der Store anweisung auf folgende Weise verwendet werden:

parity = expr.lift(cr[0])
for i in range(1,n):
    parity = expr.bit_xor(cr[i], parity)
qc.store(creg[0], parity)

Geschäft

class qiskit.circuit.Store(lvalue, rvalue)

GitHub

Basen: Instruction

Eine manuelle Speicherung eines klassischen Wertes an einem klassischen Speicherplatz.

Dies ist ein Low-Level-Primitiv der Behandlung klassischer Ausdrücke (ähnlich, wie Measure ein Primitiv für die Quantenmessung ist), und ist nicht sicher für die Unterklassifizierung.

Parameter

  • lvalue (expr.Expr) – den Speicherplatz, in den gespeichert wird.
  • rvalue (expr.Expr) – das zu speichernde Ausdrucksergebnis.
lvalue

Abrufen des l-Wertes Expr knoten, in dem gespeichert wird.

rvalue

Ermitteln des r-Wertes Expr knoten, der in den l-Wert geschrieben wird.

Echtzeit-klassische Berechnung

Siehe auch

qiskit.circuit.classical

Dokumentation auf Modulebene über die Funktionsweise der Variablen-, Ausdrucks- und Typsysteme, die zu ihrer Darstellung verwendeten Objekte und die verfügbaren klassischen Operationen.

Arbeiten mit in Echtzeit eingegebenen klassischen Daten

Die QuantumCircuit methoden für die Arbeit mit diesen Variablen im Rahmen eines einzelnen Stromkreises.

Qiskit verfügt über rudimentäre Low-Level-Unterstützung für die Darstellung klassischer Echtzeitberechnungen, die während der QPU-Ausführung stattfinden und die Ergebnisse beeinflussen. Auch bei der Hardware-Unterstützung dieser Konzepte stehen wir noch relativ am Anfang. Beachten Sie also, dass Sie die Dokumentation Ihres Hardware-Anbieters genau studieren müssen, um alle klassischen Echtzeitberechnungen optimal nutzen zu können.

Diese Echtzeitberechnungen werden durch das Ausdrucks- und Typsystem in qiskit.circuit.classical. Auf einer höheren Ebene werden alle Echtzeitausdrücke durch einen Expr knoten dargestellt, der Teil einer Ausdrucks "baum"-Darstellung ist, die auf jeder Ebene mit einer wohldefinierten Type verbunden ist. Weitere Einzelheiten zu den internen Darstellungen dieser Klassen finden Sie in der Dokumentation auf Modulebene.

Das Ergebnis einer Echtzeitberechnung Expr kann an bestimmten Stellen direkt verwendet werden. SwitchCaseOpWhileLoopOpDerzeit ist dies auf die IfElseOp Bedingungen und sowie das Ziel beschränkt. Das Ergebnis kann auch in einem typisierten klassischen Speicherort gespeichert werden, und zwar mithilfe des Store Befehls (oder seines QuantumCircuit.store() Konstruktors), der auf einem expr.Var Knoten basiert.

Ein Schaltkreis kann manuelle klassische Speicherplätze enthalten, die intern durch den Var knoten des Expr baumes. Diese haben einen angehängten klassischen Typ (wie jeder andere Ausdruck). Diese können entweder bei jeder Ausführung der Schaltung deklariert und initialisiert werden (add_var()) deklariert und initialisiert werden, oder sie sind Eingaben in die Schaltung (add_input()).

Parametrisierung zur Kompilierungszeit

Verschiedene parametrische Instruction Instanzen in Qiskit können so parametrisiert werden, dass die Auflösung bereits zur Kompilierungszeit erfolgt. Diese zeichnen sich durch die Verwendung der Parameter Klassen und ParameterExpression aus.

Kolumne „ 1 “
Kolumne „ 2 “
Parameter(Name[, UUID] )Ein symbolischer Parameter zur Kompilierzeit.
ParameterExpression(name_map, expr)Ein Parameterausdruck.

Der wesentliche Unterschied zu den expr.Var Variablen, die bei der klassischen Echtzeitberechnung verwendet werden, besteht darin, dass ParameterExpression es sich um eine symbolische Darstellung eines mathematischen Ausdrucks handelt. Die Semantik des Ausdrucks entspricht der der regulären Mathematik über den stetigen reellen Zahlen (und in bestimmten Fällen über den komplexen Zahlen). Im Gegensatz dazu Var ist ein Zeiger auf eine auf einem klassischen Computer gespeicherte Variable, wie beispielsweise einen Gleitkommawert oder eine Ganzzahl mit fester Bitbreite, die stets diskret sind.

Mit anderen Worten: Sie können davon ausgehen ParameterExpression , dass symbolische Vereinfachungen vorgenommen werden, die in der Mathematik gültig sind, wie beispielsweise die Vereinfachung von (x+y−x)/y→1(x + y - x) / y \to 1. Eine solche Vereinfachung ist in der Gleitkommaarithmetik nicht gültig und expr.Expr wird daher nicht durchgeführt.

Der "Kompilierzeit"-Teil dieser Parameter bedeutet, dass Sie den Parametern in der Regel Werte "zuweisen" wollen, bevor Sie die Schaltung zur Ausführung schicken. Diese Parameter können in der Regel überall dort verwendet werden, wo ein mathematischer Winkel erwartet wird (z. B. die Parameter eines Rotationsgatters), mit dem Vorbehalt, dass die Hardware in der Regel verlangt, dass sie vor der Ausführung einem geeigneten klassisch typisierten Wert zugewiesen werden. Sie können diese Aufgabe mit QuantumCircuit.assign_parameters().

Möglicherweise möchten Sie viele Parameter verwenden, die miteinander in Zusammenhang stehen. ParameterVectorUm dies zu vereinfachen (und zu vermeiden, dass Sie sich viele Namen ausdenken müssen), können Sie den Komfortkonstruktor verwenden. ParameterVectorElementDie Elemente des Vektors sind allesamt gültige Parameter Instanzen einer speziellen Unterklasse.

Kolumne „ 1 “
Kolumne „ 2 “
ParameterVector(Name[, Länge, UUID] )Ein Container mit vielen miteinander verbundenen Parameter Objekten.
ParameterVectorElement(Vektor, Index[, UUID] )ParameterVectorEin Element von.

Steuerungsfluss in Schaltkreisen

ControlFlowOpQuantumCircuitIn wird der klassische Kontrollfluss durch bestimmte Instructions dargestellt, die Unterklassen von sind.

Kolumne „ 1 “
Kolumne „ 2 “
ControlFlowOp(name, num_qubits, num_clbits,...)Abstrakte Klasse, die alle Kontrollflussoperationen kapselt.

Der Einfachheit halber gibt es eine frozenset Instanz, die die Instruction.name Attribute der einzelnen Kontrollflussoperationen enthält.

qiskit.circuit.CONTROL_FLOW_OP_NAMES

Menge der Befehlsnamen der bekannten Kontrollflussoperationen von Qiskit.

Die Funktion get_control_flow_name_mapping() ermöglicht den Zugriff auf die Kontrollflussoperationsklassen, die mit jedem Namen verbunden sind.

get_control_flow_name_mapping

qiskit.circuit.get_control_flow_name_mapping()

GitHub

Gibt ein Wörterbuch zurück, das die Namen der Kontrollflussoperationen den entsprechenden Klassen zuordnet."

Beispiele

from qiskit.circuit import get_control_flow_name_mapping

ctrl_flow_name_map = get_control_flow_name_mapping()
if_else_object = ctrl_flow_name_map["if_else"]

print(if_else_object)
<class 'qiskit.circuit.controlflow.if_else.IfElseOp'>

Diese Kontrollflussoperationen (IfElseOp, WhileLoopOp, SwitchCaseOp, ForLoopOp, und BoxOp) verfügen alle über einen spezifischen Zustand, der die Verzweigungsbedingungen und -strategien definiert, enthalten jedoch in ihrer blocks Eigenschaft alle verschiedenen Teilschaltkreisblöcke, die möglicherweise aufgerufen werden.

Kolumne „ 1 “
Kolumne „ 2 “
IfElseOp(Bedingung, true_body[, false_body,...] )Eine Schaltkreisoperation, die ein Programm (true_body) ausführt, wenn eine vorgegebene Bedingung (condition) als wahr bewertet wird, und andernfalls optional ein anderes Programm (false_body) auswertet.
WhileLoopOp(Bedingung, Hauptteil[, Beschriftung] )Eine Schaltungsoperation, die eine Teilschaltung (body) so lange ausführt, bis eine Bedingung (condition) als Falsch ausgewertet wird.
SwitchCaseOp(Ziel, Fälle, *[, Bezeichnung] )Eine Schaltungsoperation, die einen bestimmten Schaltungsblock auf der Grundlage des Abgleichs einer gegebenen target mit einer geordneten Liste von values ausführt.
ForLoopOp(Indexset, Schleifenparameter, Hauptteil[,...] )Eine Schaltungsoperation, die eine Teilschaltung (body), die durch einen Parameter loop_parameter parametrisiert ist, wiederholt durch die Menge der in indexset angegebenen ganzzahligen Werte ausführt.
BoxOp(Inhalt[, Dauer, Einheit, Bezeichnung, Anmerkungen] )Eine skalierte "Box" von Operationen auf einem Schaltkreis, die im größeren Kontext atomar behandelt werden.

Das SwitchCaseOp erkennt außerdem einen speziellen Wert:

qiskit.circuit.CASE_DEFAULT

Standardwert: <default case>

Ein spezielles Objekt, das den "Standardfall" einer switch-Anweisung darstellt. Wenn Sie dies als Fallziel verwenden, muss es der letzte Fall sein und wird mit allem übereinstimmen, was noch nicht übereinstimmt. Bei Verwendung der Builder-Schnittstelle von QuantumCircuit.switch()verwendet wird, kann darauf auch über das Attribut DEFAULT des gebundenen Case-Builder-Objekts zugegriffen werden.

Zusätzlich zu den Kontrollflussoperationen mit Blockstruktur gibt es zwei spezielle Anweisungen, die den Kontrollfluss innerhalb von Schleifen beeinflussen. Diese entsprechen den typischen Verwendungen der Anweisungen break und continue in klassischen Programmiersprachen.

Kolumne „ 1 “
Kolumne „ 2 “
BreakLoopOp(num_qubits, num_clbits[, label] )Eine Schaltungsoperation, die, wenn sie auftritt, zum Ende der nächstgelegenen umschließenden Schleife springt.
ContinueLoopOp(num_qubits, num_clbits[, label] )Eine Schaltkreisoperation, die, wenn sie auftritt, zur nächsten Iteration der nächstgelegenen umschließenden Schleife übergeht.
Anmerkung

Die Darstellung der Klassen ist hier dokumentiert, aber bitte beachten Sie, dass die manuelle Erstellung dieser Klassen ein Vorgang auf niedriger Ebene ist, von dem wir nicht erwarten, dass die Benutzer ihn häufig durchführen müssen.

Benutzer sollten „Hinzufügen von Kontrollfluss zu Schaltkreisen“ lesen, um die empfohlenen Arbeitsabläufe zum Erstellen von Schaltkreisen mit aktiviertem Kontrollfluss zu erfahren.

Da ControlFlowOp Unterklassen ebenfalls Instruction Unterklassen sind, bedeutet dies, dass sie aufgrund der Art und Weise, wie sie in CircuitInstruction Instanzen gespeichert sind, auf eine Folge von Qubits und Clbits in deren qubits und clbits Attributen „angewendet“ werden. Dies kann zu subtilen Problemen bei der Datenkonsistenz führen: Die Qubit Objekte und Clbit , die innerhalb der Teilschaltkreisblöcke der Kontrollflussoperationen verwendet werden, sind nicht unbedingt identisch mit den entsprechenden Objekten in der CircuitInstruction. Jeder Code, der Kontrollflussoperationen in Qiskit nutzt, muss dies berücksichtigen; innerhalb eines Teilschaltkreises sollten Sie so behandeln subcircuit.qubits[i] , als wäre es tatsächlich outer_instruction.qubits[i], und so weiter. Sie können dafür ganz einfach eine Nachschlagetabelle erstellen, indem Sie Folgendes tun:

cf_instruction: CircuitInstruction = ...
cf_operation: ControlFlowOp = cf_instruction.operation
for block in blocks:
    # Mappings of "inner" qubits/clbits to the outer ones.
    qubit_map = dict(zip(block.qubits, cf_instruction.qubits))
    clbit_map = dict(zip(block.clbits, cf_instruction.clbits))

    # ... do something with `block` ...

Denken Sie daran, dass Sie diese Informationen weitergeben müssen, wenn Sie in Unterblöcke von Kontrollflussoperationen rekursieren.

Alle Teilschaltkreisblöcke in einem ControlFlowOp müssen die gleiche Anzahl von Qubits und Clbits enthalten, die sich in derselben Reihenfolge auf dieselben äußeren Bits beziehen, damit die zip im obigen Codeblock angegebene Schleife funktioniert. Die Objekte innerhalb Bit des Kreises müssen nicht buchstäblich dieselben Objekte sein. {x: x}Bei Verwendung der Control-Flow-Builder-Schnittstelle (die – das kann gar nicht oft genug betont werden – für Benutzer dringend empfohlen wird) sorgen die Builder dafür, dass die inneren Bit-Objekte mit den äußeren Bit-Objekten identisch sind; das qubit_map im obigen Codeblock ist immer ein Mapping, aber wenn Sie die Blöcke nutzen, sollten Sie auf den Fall vorbereitet sein, dass das Mapping erforderlich ist.

Jedes ClassicalRegister„s“, das in einem Kontrollfluss-Teilkreis verwendet wird, muss auch in allen übergeordneten Blöcken vorhanden sein ( d. h. in allen übergeordneten Kontrollflussoperationen sowie im äußersten Kreis), und alle Blöcke desselben ControlFlowOp Kreises müssen dieselben Register enthalten. Auch hier sorgt die Builder-Schnittstelle dafür, dass dies der Fall ist (oder löst einen Eager-Fehler aus, falls dies nicht möglich ist).

Wenn die Low-Level-Konstruktion verwendet wird, müssen die inneren QuantumCircuit blöcke alle von ihnen verwendeten klassischen Echtzeit-Berechnungsvariablen des äußeren Bereichs manuell schließen. Dies wird dadurch gekennzeichnet, dass sich diese im iter_captured_vars() iterator für diesen Block. Bibliotheken, die diese Blöcke manuell konstruieren, müssen diese Erfassungen bei der Erstellung von Kontrollfluss-Schaltkreisblöcken verfolgen und sie dem Block mit add_capture() (oder dem Konstruktorargument captures ) in den Block einfügen, aber der Anwendercode wird in der Regel die Schnittstelle des Control-Flow-Builders verwenden, der dies automatisch erledigt.

Weitere Informationen zum Erstellen von Schaltkreisen mit Kontrollfluss finden Sie in der Dokumentation zur Kontrollflusskonstruktion.

Anweisungslokale Anmerkungen

Siehe auch

qiskit.circuit.annotation

Die Diskussion des Anmerkungsrahmens auf Modulebene, einschließlich der Definition benutzerdefinierter Anmerkungen und der Interaktion des Systems mit dem Compiler und der Serialisierung in andere Formate.

Bestimmte Schaltungsbefehle können mit befehlslokalen Anmerkungen „versehen“ werden. Ab Qiskit 2.1.0 ist dies auf BoxOp. beschränkt. Alle Annotationen sind Unterklassen eines Basisobjekts, das eine Schnittstelle definiert, stellen jedoch in der Regel vollständig benutzerdefinierte Analysen und Befehle dar.

Kolumne „ 1 “
Kolumne „ 2 “
Annotation(*args, **kwargs)Ein beliebiger Vermerk für Anweisungen.

Untersuchung von Kommutationsrelationen

Wenn zwei Operationen in einem Schaltkreis gleichwertig sind, können wir die Reihenfolge ihrer Anwendung vertauschen. Dies kann zu Optimierungen und Vereinfachungen führen, z. B. wenn es möglich ist, Gatter zusammenzulegen oder aufzuheben:

     ┌─────────┐     ┌─────────┐               ┌─────────┐
q_0: ┤ Rz(0.5) ├──■──┤ Rz(1.2) ├──■──     q_0: ┤ Rz(1.7) ├
     └─────────┘┌─┴─┐└──┬───┬──┘┌─┴─┐  =       └──┬───┬──┘
q_1: ───────────┤ X ├───┤ X ├───┤ X ├     q_1: ───┤ X ├───
                └───┘   └───┘   └───┘             └───┘

Die Durchführung dieser Optimierungen ist Teil des Transpilers, doch die Werkzeuge zur Untersuchung von Kommutationen sind in der CommutationChecker. verfügbar.

Kolumne „ 1 “
Kolumne „ 2 “
CommutationChecker([...])Prüfen Sie die Kommutationen zweier Operationen.

Verzögerte Auflösungsplanung

In der Regel kann die Ausgabe des Qiskit-Compilers nicht direkt auf einer QPU ausgeführt werden. Zunächst durchläuft es wahrscheinlich einen herstellerspezifischen Compiler auf Impulsebene, der die Logikgatter und Messwerte in Signale für die Steuerelektronik der QPU umwandelt. Zwar lassen sich mit Target Qiskit einige der zeitlichen Einschränkungen dieser Impulse abbilden, doch ist dies in der Regel nicht vollständig. Dies gilt insbesondere dann, wenn dynamische Schaltungen (Feed-Forward-Operationen) zum Einsatz kommen; die durch die klassischen Komponenten verursachten Verzögerungen hängen oft von Details der Nachoptimierung auf niedriger Ebene durch Backend-Compiler ab und können von Qiskit nicht erkannt werden.

In diesen Fällen kann der Benutzer die relative Zeitplanung der Impulse, z. B. bei der dynamischen Entkopplung, durch die Verwendung von "Streckzeiten" steuern. Diese werden konstruiert durch QuantumCircuit.add_stretch()konstruiert und interagieren mit dem klassischen Ausdrücksystem, das in qiskit.circuit.classicalbeschrieben, obwohl sie nicht in Echtzeit veränderbar sind.

Zum Beispiel können wir Strecken und Boxen hinzufügen, um ein System aufzubauen, in dem zwei separate dynamische Entkopplungssequenzen auf dasselbe Qubit angewendet werden, während ein Paar anderer Qubits eine Verzögerung von unbekannter Dauer erfährt. Die beiden Sequenzen müssen zwingend gleich lang sein, auch wenn die konkreten DD-Impulse intern unterschiedlich lang sind.

from qiskit import QuantumCircuit
from qiskit.circuit.classical import expr

qc = QuantumCircuit(3, 3)
# This sets up three duration "degrees of freedom" that will
# be resolved later by a backend compiler.
a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")

# This set of operations involves feed-forward operations that
# Qiskit cannot know the length of.
with qc.box():
    qc.h(1)
    qc.cx(1, 2)
    qc.measure([1, 2], [1, 2])
    with qc.if_test(expr.equal(qc.clbits[1], qc.clbits[2])):
        qc.h(1)

# While that stuff is happening to qubits (1, 2), we want
# qubit 0 to do two different DD sequences.  The two DD
# sequences are fixed to be the same length as each other,
# even though they're both internally stretchy.
with qc.box(duration=a):
    # Textbook NMRish XX DD.
    qc.delay(b, 0)
    qc.x(0)
    qc.delay(expr.mul(2, b), 0)
    qc.x(0)
    qc.delay(b, 0)
with qc.box(duration=a):
    # XY4-like DD.
    for _ in range(2):
        qc.delay(c, 0)
        qc.y(0)
        qc.delay(expr.mul(2, c), 0)
        qc.x(0)
        qc.delay(c, 0)

Erstellen benutzerdefinierter Anweisungen

QuantumCircuitWenn Sie einfache, einmalig verwendete Anweisungen oder Gatter erstellen möchten, die einer Schaltung hinzugefügt werden sollen, und die Blöcke lediglich zur Visualisierung oder Gruppierung dienen, ist der einfachste Weg, eine benutzerdefinierte Anweisung oder ein benutzerdefiniertes Gatter zu erstellen, deren Definition einfach als zu definieren und dann je nach Bedarf die to_instruction() Methode oder to_gate() zu verwenden. Die Ergebnisse können direkt auf QuantumCircuit.append() der größeren Schaltung ausgegeben werden. Diese Methoden erzeugen Basis- Instruction oder Gate -Instanzen, deren definition Attribut die übergebene Schaltung ist, was bedeutet, dass diese automatisch für den Transpiler sowie für andere Qiskit-Funktionen zugänglich ist, die versuchen, Schaltungen zu zerlegen.

Beachten Sie, dass eigenständige Befehle und Gatter nur auf Qubits und Clbits wirken sollten; Befehle, die einen komplexen Kontrollfluss verwenden müssen, müssen mit compose() in das QuantumCircuit eingefügt werden.

Erstellen von Unterklassen für Anweisungen

Die Basisklassen Instruction, Gate und ControlledGate sind alle so konzipiert, dass sie sicher unterklassifiziert werden können, und verfügen über Anknüpfungspunkte, die von Unterklassen implementiert werden können. qiskit.circuit.singletonWenn Ihr benutzerdefiniertes Gate parameterlos und zustandslos ist, möchten Sie möglicherweise auch von der entsprechenden Singleton-Klasse in ableiten, beispielsweise SingletonGate. Weitere Methoden und Hook-Punkte für die Singleton-Mechanik finden Sie in qiskit.circuit.singleton der Dokumentation unter.

Unterklassen sollten in der Regel einen Standardkonstruktor definieren, der den Konstruktor :class`super` mit den für Ihre Anweisung korrekten Argumenten aufruft. Instruction.paramsEs ist zwar zulässig, zusätzlichen Zustand in der Klasse zu haben, doch lassen sich Ihre Unterklassen am zuverlässigsten in die übrige Qiskit-Infrastruktur integrieren, wenn Sie sich ausschließlich auf Ihre stützen und diese Parameter ausschließlich aus Gatterwinkeln bestehen.

Unterklassen von Instruction (oder einer seiner Unterklassen) sollten die private Instruction._define() Methode implementieren, die den verborgenen _definition Cache, der der öffentlichen definition Methode zugrunde liegt, verzögert befüllt.

_define

Instruction._define()

GitHub

InstructionFüllen Sie das Feld „cached“ _definition dieses aus.

Unterklassen sollten diese Methode implementieren, um eine verzögerte Initialisierung ihres öffentlichen definition Attributs zu ermöglichen. Eine Unterklasse kann ihre params zum Zeitpunkt des Aufrufs nutzen. Die Methode sollte mit einem QuantumCircuit befüllen _definition und keinen Wert zurückgeben.

In Unterklassen von ControlledGate sollte die _define() Methode die Zerlegung nur für den Steuerzustand „alles Einsen“ implementieren. Das ControlledGate.definition System passt dies entsprechend an, um den tatsächlichen Steuerungszustand zu berücksichtigen.

Wenn die Unterklasse die Singleton-Maschinerie verwendet, ist zu beachten, dass _define() unmittelbar nach der Ausführung der Anweisung class-body eifrig aufgerufen wird, um das Definitionsobjekt für das kanonische Singleton-Objekt zu erzeugen. Das bedeutet, dass Ihre Definition nur Gatter verwenden darf, die bereits definiert sind. Wenn Sie eine Bibliothek mit vielen Singleton-Gattern schreiben, müssen Sie Ihre Dateien und Importe so anordnen, dass dies möglich ist.

Unterklassen von Gate werden wahrscheinlich ebenfalls die Instanzmethode des Numpy-Array-Protokolls, __array__, überschreiben wollen. Dies wird von Gate.to_matrix()… verwendet und hat folgende Signatur:

__array__

object.__array__(dtype=None, copy=None)

Gibt ein NumPy-Array zurück, das das Gatter darstellt. Dabei kann das Feld des params Gates verwendet werden, wobei davon ausgegangen werden kann, dass es sich um numerische Werte handelt (sofern die Unterklasse dies erwartet) und nicht um Parameter zur Kompilierungszeit.

Für größtmögliche Effizienz sollte das zurückgegebene Array standardmäßig einen dtype von complex.

Wenn Ihre benutzerdefinierte Unterklasse über natürliche Darstellungen ihrer kontrollierten oder inversen Formen verfügt, möchten Sie möglicherweise auch die inverse() Methoden und control() überschreiben.

Als Beispiel für die Definition eines benutzerdefinierten „ RxzR_{xz} “-Gates, d. h. einer Drehung um einen einzigen Winkel um die Achse XZXZ. RZXGateIm Grunde genommen wäre es so, wenn die Qubits umgekehrt angeordnet wären; daher werden wir unsere Definition entsprechend formulieren. GateWir sind parametrisch, können also kein Singleton sein, aber wir sind unitär, sollten also ein sein:

import math
import numpy as np
from qiskit.circuit import Gate, QuantumCircuit

class RXZGate(Gate):
    def __init__(self, theta):
        # Initialize with our name, number of qubits and parameters.
        super().__init__("rxz", 2, [theta])

    def _define(self):
        # Our base definition is an RZXGate, applied "backwards".
        defn = QuantumCircuit(2)
        defn.rzx(1, 0)
        self._definition = defn

    def inverse(self, annotated = False):
        # We have an efficient representation of our inverse,
        # so we'll override this method.
        return RXZGate(-self.params[0])

    def power(self, exponent: float):
        # Also we have an efficient representation of power.
        return RXZGate(exponent * self.params[0])

    def __array__(self, dtype=None, copy=None):
        if copy is False:
            raise ValueError("unable to avoid copy while creating an array as requested")
        cos = math.cos(0.5 * self.params[0])
        isin = 1j * math.sin(0.5 * self.params[0])
        return np.array([
            [cos, -isin, 0, 0],
            [-isin, cos, 0, 0],
            [0, 0, cos, isin],
            [0, 0, isin, cos],
        ], dtype=dtype)

SessionEquivalenceLibraryRZXGateIn diesem Beispiel haben wir eine Basendefinition in Bezug auf definiert, doch um schnellere Zerlegungen in eine Reihe von Basen zu ermöglichen, möchten wir vielleicht noch einige weitere Äquivalenzen zu hinzufügen. Beachten Sie, dass die BasisTranslator Übersetzungssuche alle möglichen Äquivalenzen in allen möglichen Tiefen durchsucht; wenn Sie also eine Äquivalenz beispielsweise in Bezug auf angeben, XGate stehen automatisch auch Zerlegungen in Bezug auf RXGate zur Verfügung.

Fügen wir eine Äquivalenz in Form von HH, CXCX und RzR_z für einen beliebigen symbolischen Parameter hinzu:

from qiskit.circuit import SessionEquivalenceLibrary, Parameter

theta = Parameter("theta")

equiv = QuantumCircuit(2)
equiv.h(0)
equiv.cx(1, 0)
equiv.rz(theta, 0)
equiv.cx(1, 0)
equiv.h(0)

SessionEquivalenceLibrary.add_equivalence(RZXGate(theta), equiv)

Danach werden Übersetzer wie BasisTranslator während der gesamten Dauer der „ Python “-Interpreter-Sitzung unsere neue Definition bei ihrer Suche finden.


Arbeiten mit Objekten auf Schaltkreisebene

Umwandlung abstrakter Schaltungen in physikalische Schaltungen

Eine abstrakte QuantumCircuit kann nicht zuverlässig auf Hardware ausgeführt werden. Sie können vielleicht einige der High-Level-Simulatoren verwenden, die in Simulation von Schaltungen verlinkt sind, um schnelle Ergebnisse für kleine Schaltungen zu erzielen, aber um Schaltungen im Nutzmaßstab zu betreiben, müssen Sie echte Hardware verwenden, was die Kompilierung zu einer physischen Schaltung erfordert.

Die entsprechende Funktion auf hoher Ebene lautet transpile(); sie nimmt eine abstrakte Schaltung sowie eine Hardware backend oder targetals Argumente entgegen und gibt eine physikalische Schaltung zurück. Um mehr Zugriff und Kontrolle über die Phasen der auszuführenden Durchläufe zu erhalten, erstellen Sie zunächst mithilfe generate_preset_pass_manager() von eine StagedPassManager , die Sie anschließend anpassen können.

Die gesamte Transpilierungs- und Kompilierungsmaschinerie wird in der qiskit.transpiler modul-Dokumentation beschrieben, und Einzelheiten zu allen in Qiskit eingebauten Übergängen finden Sie in qiskit.transpiler.passes.

Schaltungen simulieren

Dies ist zwar nicht Teil der qiskit.circuit schnittstelle, aber eine der häufigsten Anforderungen ist es, schnelle Simulationsergebnisse für QuantumCircuit objekte. Dieser Abschnitt bietet einen schnellen Übergang zu anderen Stellen in der Dokumentation, an denen Sie die entsprechenden Informationen finden.

Bei unitären Schaltkreisen können Sie die Auswirkungen auf den Zustand von ∣0⋯0⟩\lvert0\dotsm0\rangle simulieren, indem Sie QuantumCircuit direkt an den Statevector Standardkonstruktor übergeben. Ebenso können Sie eine Einheitsmatrix erhalten, die den Schaltkreis als Operator darstellt, indem Sie diese an den Operator Standardkonstruktor übergeben. Wenn Sie über einen physikalischen Schaltkreis verfügen, können Sie diesen stattdessen an Operator.from_circuit() die Methode übergeben, um Transformationen aus dem QuantumCircuit.layout anzuwenden und ihn so wieder in den „abstrakten“ Qubit-Raum abzubilden.

Für ein Backend-ähnliches Simulationserlebnis gibt es Simulator-gestützte Implementierungen aller Qiskit-Hardware-Schnittstellen. Das könnte Sie besonders interessieren:

Äquivalenzrelationen definieren

Eine häufige Aufgabe bei der Abbildung abstrakter Schaltungen auf physikalische Hardware und der Optimierung des Ergebnisses besteht darin, Äquivalenzrelationen zu finden, die ein Gatter auf einen anderen Basissatz abbilden. Qiskit speichert diese Informationen in einer Datenbankklasse namens EquivalenceLibrary.

Kolumne „ 1 “
Kolumne „ 2 “
EquivalenceLibrary( [Basis] )Eine Bibliothek, die ein einseitiges Mapping von Gates auf ihre äquivalenten Implementierungen als QuantumCircuits bereitstellt.

Qiskit wird mit einer großen Anzahl von vordefinierten Äquivalenzbeziehungen für alle Standardgatter ausgeliefert. Diese Basisbibliothek heißt StandardEquivalenceLibraryund sollte als unveränderlich behandelt werden.

qiskit.circuit.StandardEquivalenceLibrary

Ein EquivalenceLibrary , das alle in Qiskit integrierten Standard-Gatterbeziehungen speichert. SessionEquivalenceLibrarybaseSie sollten diese Variable nicht ändern, sondern stattdessen entweder eine eigene EquivalenceLibrary erstellen, die diese als Vorlage verwendet, oder den globalen Zustand anpassen.

Qiskit definiert außerdem ein gemeinsames Objekt für den globalen Zustand, SessionEquivalenceLibrary, das an verschiedenen Stellen in Qiskit als Standardäquivalenz verwendet wird, insbesondere im BasisTranslator Transpiler-Durchlauf. BasisTranslatorSie können gerne mithilfe der entsprechenden add_equivalence() Methode eigene Entsprechungen hinzufügen; diese werden dann standardmäßig von den Instanzen der Klasse übernommen.

qiskit.circuit.SessionEquivalenceLibrary

Die Standardinstanz von EquivalenceLibrary, die von den meisten Qiskit-Objekten verwendet wird, sofern keine Bibliothek manuell angegeben wird. add_equivalence()Sie können gerne mithilfe von […] weitere Äquivalenzen hinzufügen. Es übernimmt alle integrierten Regeln von StandardEquivalenceLibrary.

Wende das Pauli-Prinzip auf einen Stromkreis an

Bei der Ausführung von Quantenschaltungen gibt es zwei Hauptarten von Rauschen. Das erste ist stochastisches oder inkohärentes Rauschen, das hauptsächlich auf die unerwünschte Wechselwirkung zwischen dem Quantenprozessor und der äußeren Umgebung, in der er sich befindet, zurückzuführen ist. Der zweite ist als kohärenter Fehler bekannt, und diese Fehler entstehen durch eine unvollkommene Kontrolle eines Quantensystems. Dabei kann es sich um unerwünschte Terme in einem System-Hamiltonian handeln, d. h. um eine fehlerhafte unitäre Entwicklung, oder um Fehler, die durch eine fehlerhafte zeitliche Steuerung des Quantensystems entstehen, wie z. B. falsche Impulsformen für Gatter.

Pauli-Twirling ist eine Technik zur Unterdrückung von Quantenfehlern, bei der kohärente Fehler in stochastische Fehler umgewandelt werden, indem die Ergebnisse vieler zufälliger, aber logisch gleichwertiger Schaltungen miteinander kombiniert werden. Qiskit bietet eine Funktion zur Anwendung von Pauli Twirling auf eine gegebene Schaltung für Standard-Zweibit-Gatter. Weitere Einzelheiten finden Sie in der nachstehenden Dokumentation zu dieser Funktion:

pauli_twirl_2q_gates

qiskit.circuit.pauli_twirl_2q_gates(circuit, twirling_gate=None, seed=None, num_twirls=None, target=None)

GitHub

Erstellen Sie Kopien eines gegebenen Schaltkreises mit Pauli-Twirling, das um bestimmte zwei Qubit-Gatter angewendet wird.

Wenn Sie diese Funktion mit der Absicht ausführen, eine Schaltung für den Betrieb auf Hardware zu zwirbeln, ist dies möglicherweise nicht die effizienteste Art, das Zwirbeln durchzuführen. Insbesondere wenn der Hardwarehersteller die primitives ausführungsschnittstelle mit SamplerV2 und EstimatorV2 implementiert hat, ist dies höchstwahrscheinlich nicht der beste Weg, um Twirling auf Ihre Schaltung anzuwenden, und Sie sollten sich auf die Implementierung von SamplerV2 und/oder EstimatorV2 für den angegebenen Hardwarehersteller beziehen.

Wenn diese Funktion nach transpile() ausgeführt werden soll, PassManager.run() kann das optionale target Argument verwendet werden, damit die eingefügten 1-Qubit-Pauli-Gatter so synthetisiert werden, dass sie mit dem angegebenen Target kompatibel sind, sodass die Ausgangsschaltung(en) weiterhin kompatibel bleiben.

Parameter

  • circuit (QuantumCircuit) – Der Kreislauf zum Wirbeln
  • twirling_gate (None | str |Gate |list[str] | list[Gate]) – Das „Twirl“-Gate ist standardmäßig auf „None“ gesetzt, was bedeutet, dass alle Standard-Gates – CXGate, CZGate, ECRGate, und iSwapGate– gedreht werden. Falls angegeben, kann es sich entweder um ein einzelnes Gate oder um eine Liste von Gates handeln, entweder als Gate-Objekt oder als dessen String-Name. Derzeit werden nur die Bezeichnungen „cx“, „cz“, „ecr“ und „iswap“ unterstützt. Wenn ein Gate-Objekt außerhalb der Standard-Gates bereitgestellt wird, muss über seine to_matrix Methode eine Matrix definiert sein, damit das Gate möglicherweise gedreht werden kann. Wenn keine gültige Twirling-Konfiguration berechnet werden kann, wird dieses bestimmte Gate stillschweigend ignoriert und nicht getwirlt.
  • seed (int | None) – Ein ganzzahliger Seed für den Zufallszahlengenerator, der intern von dieser Funktion verwendet wird. Falls angegeben, muss dieser Wert zwischen 0 und 18.446.744.073.709.551.615 liegen.
  • num_twirls (int | None) – Die Anzahl der zu bauenden Wirbelkreise. Die Standardeinstellung ist None und liefert einen einzelnen Stromkreis. Wenn es sich um eine ganze Zahl handelt, wird eine Liste von Schaltkreisen mit num_twirls-Schaltkreisen zurückgegeben.
  • target (Target | None) – Falls angegeben, eine Target Instanz, die für die Durchführung der Einzel-Qubit-Dekomposition im Rahmen des Pauli-Twirling verwendet wird, um die dem Schaltkreis hinzugefügten Pauli-Gates zu optimieren und auf das angegebene Ziel abzubilden.

Rückgabe

Eine Kopie der gegebenen Schaltung mit Pauli-Twirling, das auf jede Instanz des angegebenen Twirling-Gates angewendet wird.

Rückgabetyp

QuantumCircuit | Liste [ QuantumCircuit ]


Ausnahmen

Fast alle Circuit-Funktionen und -Methoden lösen einen CircuitError aus, wenn ein Fehler auftritt, der speziell auf die Verwendung von Qiskit zurückzuführen ist (im Gegensatz zu normalen Tipp- oder Indizierungsproblemen, die normalerweise den entsprechenden Standardfehler Python auslösen).

CircuitError

exception qiskit.circuit.CircuitError(*message)

GitHub

Basen: QiskitError

Basisklasse für Fehler, die bei der Verarbeitung eines Stromkreises auftreten.

Legen Sie die Fehlermeldung fest.


Schaltungskonventionen

Bei der Konstruktion von Schaltkreisen aus abstrakten Objekten und konkreteren Matrizen gibt es mehrere mögliche Konventionen für die Bit-Beschriftung, die Bit-Reihenfolge und die Umsetzung des abstrakten Tensorprodukts in konkrete Matrixalgebra.

Die Konventionen von Qiskit sind:

  • in Bitstring-Darstellungen werden die Bits mit dem am weitesten rechts stehenden Bit in der Zeichenfolge 00 und dem am weitesten links stehenden Bit in der Zeichenfolge von nn n−1n - 1 bezeichnet.
  • bei der Verwendung ganzer Zahlen als Bitspezifizierungsindizes in Funktionen zur Schaltungskonstruktion wird die ganze Zahl als Index in QuantumCircuit.qubits (oder clbits).
  • beim Zeichnen von Schaltkreisen werden die Bits mit dem niedrigsten Index nach oben gesetzt.
  • in Zustandsvektor-Darstellungen realisieren wir das abstrakte Tensorprodukt als Kronecker-Produkt und ordnen die Argumente dazu so an, dass die Amplitude des rechnerischen Basiszustands ∣x⟩\lvert x\rangle, wobei xx die als Ganzzahl interpretierte Bitfolge ist, an der Stelle statevector[x] liegt.
  • bei der Steuerung eines Gatters steht das Kontroll-Qubit in der Argumentliste an erster Stelle, z. B. ist bei dem Aufruf qc.cx(0, 1) das Qubit 0 die Steuerung und das Qubit 1 das Ziel. In ähnlicher Weise wird beim manuellen Aufruf qc.append(CXGate(), [0, 1]) das Qubit 0 die Kontrolle und das Qubit 1 das Ziel sein.

Wir wollen diese Konventionen anhand einiger Beispiele erläutern.

Bit-Kennzeichnung

Nehmen Sie den Rundkurs:

from qiskit import QuantumCircuit

qc = QuantumCircuit(5, 5)
qc.x(0)
qc.x(1)
qc.x(4)
qc.measure(range(5), range(5))

Dadurch werden die Zustände der Qubits 0, 1 und 4 von ∣0⟩\lvert0\rangle auf ∣1⟩\lvert1\rangle umgedreht, dann werden alle Qubits nn mit Hilfe der Berechnungsbasis ( ZZ ) in das entsprechende Qubit nn umgerechnet. Bei einer geräuschlosen Simulation wird die von dieser Schaltung ausgegebene Bitfolge jedes Mal 1001110011 sein; die Qubits 0, 1 und 4 werden umgedreht, und die "Eins"-Werte in der Bitfolge befinden sich an der nullten, ersten und vierten Stelle von rechts.

In Qiskit würden wir den Qubit-Zustand unmittelbar vor der Messung in der Kurzschrift ket-notation als ∣10011⟩\lvert10011\rangle schreiben. Beachten Sie, dass die ket-Beschriftung mit dem klassischen Bitstring übereinstimmt und den numerischen Binärwert 19 hat.

Wenn wir diese Schaltung zeichnen, werden wir sehen, dass Qiskit das nullte Qubit an die Spitze der Schaltungszeichnung setzt:

qc.draw("mpl")
Schaltplan, der durch den vorherigen Code ausgegeben wurde.

Matrixdarstellungen

Zustandsvektoren werden nach der Konvention definiert, dass für ein zweistufiges System die Beziehung zwischen abstrakter Darstellung und Matrixdarstellung so ist, dass

α∣0⟩+β∣1⟩↔(αβ)\alpha\lvert0\rangle + \beta\lvert1\rangle \leftrightarrow \begin{pmatrix} \alpha \\ \beta \end{pmatrix}

wobei α\alpha und β\beta komplexe Zahlen sind. Wir speichern den Zustandsvektor als 1D Numpy ndarray mit Daten sv = [alpha, beta], d.h. sv[0] == alpha und sv[1] == beta; beachten Sie, dass die Indizes im Zustandsvektor mit den Ket-Bezeichnungen übereinstimmen.

Wir konstruieren das Tensorprodukt zweier Qubit-Zustände in der Matrixalgebra unter Verwendung des Kronecker-Produkts, mit Qubit 0 auf der rechten Seite und Qubit 1 auf der linken Seite, so dass der ZZ Basiszustand ∣x⟩\lvert x\rangle (wobei xx die ganzzahlige Interpretation der Bitkette ist) seinen Nicht-Null-Term im Zustandsvektor sv auf sv[x] hat:

import numpy
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector

state_0 = [1, 0]  # defined representation of |0>
state_1 = [0, 1]  # defined representation of |1>

# Circuit that creates basis state |10011>, where
# binary 10011 has the decimal value 19.
qc = QuantumCircuit(5)
qc.x(0)
qc.x(1)
qc.x(4)
qiskit_sv = Statevector(qc)

# List index 'n' corresponds to qubit 'n'.
individual_states = [
    state_1,
    state_1,
    state_0,
    state_0,
    state_1,
]
# Start from a scalar.
manual_sv = [1]
for qubit_state in individual_states:
    # Each new qubit goes "on the left".
    manual_sv = numpy.kron(qubit_state, manual_sv)

# Now `qiskit_sv` and `manual_sv` are the same, and:
assert manual_sv[19] == 1
assert qiskit_sv[19] == 1

Dies schlägt sich in der Matrixdarstellung von Operatoren nieder und steht im Einklang mit den Konventionen zur Bitreihenfolge bei kontrollierten Operatoren. Beispielsweise lautet die Matrixform von CXGate wie folgt:

import numpy
from qiskit.circuit.library import CXGate

numpy.array(CXGate())
array⁡(CX)=(1000000100100100)\operatorname{array}(CX) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \end{pmatrix}

Dies mag sich von anderen Matrixdarstellungen, die Sie für CXCX gesehen haben, unterscheiden, aber bedenken Sie, dass die Wahl der Matrixdarstellung konventionell ist und diese Form den Konventionen von Qiskit entspricht, wonach die Kontroll-Qubits an erster Stelle stehen und das Tensorprodukt so dargestellt wird, dass es eine Entsprechung zwischen dem Index der "einen Amplitude" und dem Bitstring-Wert eines Zustands gibt.

Bei mehreren Steuerelementen für ein Gatter, wie beispielsweise bei CCXGate, wird das ctrl_state Argument als Bitfolge-Wert der Steuer-Qubits interpretiert, wobei dieselben, auf Null basierenden Nummerierungskonventionen verwendet werden. CCXGateDa beispielsweise der Standardwert ctrl_state die Bitstring aus lauter Einsen ist, lässt sich erkennen, dass die Matrixform von CCXGate mit ctrl_state = 1 derselben Form entspricht, als hätten wir den Kontrollzustand aus lauter Einsen gewählt, dabei jedoch den Wert des Kontroll-Qubits mit der höheren Indizierung beim Eintritt in das Gatter und beim Verlassen des Gatters umgekehrt:

from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator

# Build the natural representation of `CCX` with the
# control qubits being `[0, 1]`, relative to the
# bitstring state "01", such that qubit 0 must be in |1>
# and qubit 1 must be in |0>.  The target qubit is 2.
ccx_natural = QuantumCircuit(3)
ccx_natural.ccx(0, 1, 2, ctrl_state=1)

# Build the same circuit in terms of the all-ones CCX.
# Note that we flip _qubit 1_, because that's the one
# that differs from the all-ones state.
ccx_relative = QuantumCircuit(3)
ccx_relative.x(1)
ccx_relative.ccx(0, 1, 2)
ccx_relative.x(1)

assert Operator(ccx_relative) == Operator(ccx_natural)

In beiden Fällen lautet die Matrixform von CCXGate in ctrl_state = 1 wie folgt:

array⁡(CCX(ctrl_state=1))=(1000000000000100001000000001000000001000010000000000001000000001)\operatorname{array}\bigl(CCX(\text{ctrl\_state}=1)\bigr) = \begin{pmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{pmatrix}
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.