Approximativer Quantencompiler
qiskit.synthesis.unitary.aqc
Implementierung des approximativen Quantencompilers, wie in der Abhandlung [1] beschrieben.
Schnittstelle
Die öffentliche Hauptschnittstelle dieses Moduls erreicht man, indem man unitary_synthesis_method='aqc' an transpile(). Dadurch wird die Synthesemethode auf AQCSynthesisPlugin umgestellt. Die einzelnen Klassen sind:
Kolumne „ 1 “ | Kolumne „ 2 “ |
|---|---|
AQC( [Optimierer, Startwert] ) | Eine generische Implementierung des Approximate Quantum Compilers. |
ApproximateCircuit(Anzahl_Qubits[, Name] ) | Eine Basisklasse, die eine ungefähre Schaltung darstellt. |
ApproximatingObjective() | Eine Basisklasse für die Definition eines Optimierungsproblems. |
CNOTUnitCircuit(num_qubits, cnots[, tol, name] ) | Eine Klasse, die eine ungefähre Schaltung auf der Grundlage von CNOT-Einheitsblöcken darstellt. |
CNOTUnitObjective(num_qubits, cnots) | Eine Basisklasse für eine Problemdefinition auf der Grundlage der CNOT-Einheit. |
DefaultCNOTUnitObjective(num_qubits, cnots) | Eine naive Umsetzung der Zielfunktion auf der Grundlage von CNOT-Einheiten. |
FastCNOTUnitObjective(num_qubits, cnots) | Implementierung einer Zielfunktion und eines Gradientenrechners, der ähnlich wie DefaultCNOTUnitObjective ist, aber um ein Vielfaches schneller. |
Mathematische Details
Wir interessieren uns für die Kompilierung einer Quantenschaltung, die wir als Suche nach der besten Schaltungsrepräsentation in Form einer geordneten Gatterfolge einer unitären Zielmatrix mit einigen zusätzlichen Hardwarebeschränkungen formalisieren. Insbesondere betrachten wir Darstellungen, die in Bezug auf die Hardware-Konnektivität sowie die Gattertiefe eingeschränkt werden können, und wir wählen eine Gatterbasis in Form von CNOT- und Rotationsgattern. Wir erinnern daran, dass die Kombination von CNOT und Rotationstoren in universell ist und daher die Kompilierung nicht einschränkt.
Um genau zu definieren, was wir unter der besten Schaltungsdarstellung verstehen, definieren wir die Metrik als die Frobenius-Norm zwischen der unitären Matrix der kompilierten Schaltung und der Ziel-Unitar-Matrix , d. h. . Diese Wahl ist durch Überlegungen der mathematischen Programmierung begründet und steht im Zusammenhang mit anderen Formulierungen, die in der Literatur zu finden sind. Schauen wir uns das Problem einmal genauer an.
sei die Anzahl der Qubits und . Bei einer CNOT-Struktur und einem Vektor von Drehwinkeln bildet die parametrische Schaltung eine Matrix . Wenn uns eine Zielschaltung gegeben wird, die eine Matrix bildet, dann möchten wir berechnen
wobei das innere Produkt das innere Produkt von Frobenius ist. Beachten Sie, dass für alle Einheiten und gilt, so dass das Ziel eine Reichweite von hat.
Unsere Strategie ist es, Folgendes zu maximieren
unter Verwendung seiner Steigung. Wir werden nun die Einzelheiten anhand eines Beispiels erläutern.
Während der Bereich von konstruktionsbedingt eine Teilmenge von ist, kann die Zielschaltung eine allgemeine unitäre Matrix bilden. Für jede ,
Daher sollten wir die Zielschaltung durch ihre globale Phase normalisieren und dann die normalisierte Schaltung annähernd kompilieren. Wir können die globale Phase später wieder einfügen.
In dem Algorithmus bezeichnet die nicht-normierte Zielmatrix und die normierte Zielmatrix. Da wir nun haben, geben wir die Gradientenfunktion an den Optimierer der Nesterov-Methode und berechnen .
Um die globale Phase wieder einzufügen, können wir den Steuerkreis wie folgt bilden
Man beachte, dass wir die Nesterov-Methode in der Arbeit zwar optimiert haben, aber nur wegen ihrer Konvergenzgarantien, nicht wegen ihrer Geschwindigkeit in der Praxis. Es ist viel schneller, L-BFGS zu verwenden, das in dieser Implementierung als Standardoptimierer eingesetzt wird.
Eine grundlegende Anwendung des AQC-Algorithmus sollte die folgenden Schritte umfassen:
# Define a target circuit as a unitary matrix
unitary = ...
# Define a number of qubits for the algorithm, at least 3 qubits
num_qubits = round(math.log2(unitary.shape[0]))
# Choose a layout of the CNOT structure for the approximate circuit, e.g. ``spin`` for
# a linear layout.
layout = options.get("layout") or "spin"
# Choose a connectivity type, e.g. ``full`` for full connectivity between qubits.
connectivity = options.get("connectivity") or "full"
# Define a targeted depth of the approximate circuit in the number of CNOT units.
depth = int(options.get("depth") or 0)
# Generate a network made of CNOT units
cnots = make_cnot_network(
num_qubits=num_qubits,
network_layout=layout,
connectivity_type=connectivity,
depth=depth
)
# Create an optimizer to be used by AQC
optimizer = partial(scipy.optimize.minimize, method="L-BFGS-B")
# Create an instance
aqc = AQC(optimizer)
# Create a template circuit that will approximate our target circuit
approximate_circuit = CNOTUnitCircuit(num_qubits=num_qubits, cnots=cnots)
# Create an objective that defines our optimization problem
approximating_objective = DefaultCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)
# Run optimization process to compile the unitary
aqc.compile_unitary(
target_matrix=unitary,
approximate_circuit=approximate_circuit,
approximating_objective=approximating_objective
)Nun ist approximate_circuit eine Schaltung, die die Zielunitarität bis zu einem gewissen Grad annähert und anstelle der ursprünglichen Matrix verwendet werden kann.
Dazu wird eine Hilfsfunktion verwendet, make_cnot_network.
make_cnot_network
qiskit.synthesis.unitary.aqc.make_cnot_network(num_qubits, network_layout='spin', connectivity_type='full', depth=0)
Erzeugt ein Netzwerk, das aus Bausteinen besteht, die jeweils ein CNOT-Gatter und möglicherweise einige Ein-Qubit-Gatter enthalten. Dieses Netz modelliert einen fraglichen Quantenoperator. Man beachte, dass jeder Baustein 2 Eingänge und Ausgänge hat, die einem Qubit-Paar entsprechen. Was wir hier tatsächlich zurückgeben, ist eine Kette von Indizes von Qubit-Paaren, die von jedem Baustein in einer Reihe gemeinsam genutzt werden.
Parameter
- num_qubits (int) – anzahl der Qubits.
- network_layout (str) – art der Netzgeometrie,
{"sequ", "spin", "cart", "cyclic_spin", "cyclic_line"}. - connectivity_type (str) – art der Inter-Qubit-Konnektivität,
{"full", "line", "star"}. - depth (int) – tiefe des CNOT-Netzes, d. h. die Anzahl der Schichten, wobei jede Schicht aus einem einzelnen CNOT-Block besteht; der Standardwert wird gewählt, wenn
L <= 0.
Rückgabe
Eine Matrix der Größe (2, N) Matrix, die die Schichten im cnot-Netz definiert, wobei N
ist entweder gleich L oder durch einen konkreten Typ des Netzes definiert.
Erhöht
ValueError - wenn ein nicht unterstützter Typ des CNOT-Netz-Layouts oder eine nicht unterstützte Anzahl von Qubits oder eine nicht unterstützte Kombination von Parametern übergeben wird.
Rückgabetyp
Man kann die Vorteile einer beschleunigten Version der Zielfunktion nutzen. Er implementiert denselben mathematischen Algorithmus wie der Standardalgorithmus DefaultCNOTUnitObjective , läuft aber um ein Vielfaches schneller. Die Instanziierung der beschleunigten Zielfunktionsklasse ist ähnlich wie im Standardfall:
# Erstellen eines Ziels, das unser Optimierungsproblem definiert approximating_objective = FastCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)
Der Rest des Codes im obigen Beispiel ändert sich nicht.
Referenzen
[1] : Liam Madden, Andrea Simonetto, Best Approximate Quantum Compiling Problems.