[PYTHON] Folgen Sie dem QAOA-Fluss (VQE) auf der Quellcode-Ebene von Blueqat

QAOA und VQE

QAOA (Quantum Approximate Optimization Algorithm) ist ein Algorithmus, der das Ging-Modell unter Verwendung eines Quantencomputers vom Typ Quantum Gate optimiert. Darüber hinaus ist VQE (Variational Quantum Eigensolver) ein Algorithmus, der die Eigenwerte einer Matrix unter Verwendung eines Quantencomputers vom Typ Quantum Gate findet und häufig für quantenchemische Berechnungen verwendet wird.

In den letzten Jahren wurde die Entwicklung von QAOA und VQE aktiv vorangetrieben, da selbst ein Quantencomputer ohne Fehlerkorrektur recht gut funktioniert.

Auf der Ebene der Quantencomputerbibliotheken wird QAOA häufig als eine Art VQE behandelt, und Blueqat behandelt QAOA auch als eine Art VQE.

Das Problem, das Sie mit VQE / QAOA lösen möchten

Gegeben eine Matrix $ \ hat H $ namens Hamiltonian. Für diese Matrix ist $ \ boldsymbol {X ein Vektor der Norm 1 mit dem kleinsten $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ (wobei $ \ cdot $ das innere Produkt ist). VQE / QAOA kann das Problem lösen, wie hoch der Wert von $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ bei der Suche nach} $ ist. Abhängig von der Form des Hamilton-Operators und dem Zweck der Lösung des Problems wird es als QAOA oder VQE bezeichnet.

Außerdem wird $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ auch als "Energie" bezeichnet. Dies liegt daran, dass dies in der Quantenmechanik tatsächlich der Energiegleichung entspricht.

Wenn dies effizient gelöst werden kann

Es gibt Anwendungen wie.

Rauer VQE-Fluss

Quantencomputer sind gut darin, riesige Matrizen zu erzeugen, sie mit Vektoren zu multiplizieren, die als Quantenbits bezeichnet werden, und Bitfolgen gemäß der resultierenden Wahrscheinlichkeitsverteilung abzutasten.

Ein Quantencomputer ist ungefähr eine Vorrichtung, die eine "Quantenschaltung" betreibt, die durch Kombinieren von Quantengattern hergestellt wird. Wenn Sie eine Quantenschaltung passieren, wird die Bitfolge abgetastet.

Da $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $ aus dem Abtastergebnis der Bitfolge erhalten werden kann, übergeben Sie die Quantenschaltung an den Quantencomputer, während Sie die Quantenschaltung nach und nach ändern, und dann $ \ Finden Sie eine Quantenschaltung, die das Boldsymbol {X} \ cdot \ hat H \ Boldsymbol {X} $ minimiert.

Wenn du es willst

Kann erhalten werden.

Während Sie den Quantenkreis nach und nach ändern?

Einige Quantengatter entsprechen der Operation "Quantenbit drehen". Indem der Drehwinkel als Parameter verwendet wird, ist es möglich, eine Quantenschaltung gemäß dem Parameter zu erzeugen.

Da der Winkel nur ein Gleitkommawert ist, Parameter (Gleitkomma-Typ) → Quantenschaltung → Abtastergebnis der Bitfolge → Energie (Gleitkomma-Typ) Sie können sich das als "Funktion vorstellen, die einen Gleitkommatyp zurückgibt, wenn Sie ihm einen Gleitkommatyp geben".

Wenn Sie diese Funktion minimieren, erhalten Sie das gewünschte Ergebnis. Oft wird für diese Optimierungen "scipy.optimize.minimize" verwendet. In einigen Fällen kann die Bayes'sche Optimierung usw. verwendet werden.

Umstände, die dem Quantencomputersimulator eigen sind

In der tatsächlichen Maschine des Quantencomputers wurde die Bitfolge durch Abtasten erhalten (indem viele Male dieselbe Quantenschaltung berechnet und das Ergebnis viele Male genommen wurde). Dies liegt daran, dass der interne Zustand des Quantencomputers (manchmal als Zustandsvektor, Wellenfunktion usw. bezeichnet) nicht so extrahiert werden kann, wie er ist.

Andererseits kann im Fall des Simulators, da der interne Zustand als Array gespeichert ist, er so extrahiert werden, wie er ist, und die Wahrscheinlichkeitsverteilung der Bitfolge kann effizienter erhalten werden als die mehrfache Berechnung derselben Quantenschaltung.

Beim Lesen von VQE- und QAOA-Papieren ist es sehr wichtig zu berücksichtigen, ob es sich um einen Simulator oder eine tatsächliche Maschine handelt, da dies nicht nur die Berechnungsgeschwindigkeit, sondern auch die Berechnungsgenauigkeit beeinflusst.

Versuche ein Bild zu machen

Mit anderen Worten, das ist es. vqe.svg.png

Schreiben Sie mit Blueqat

In QAOA wird der Hamilton-Operator nur unter Verwendung der sogenannten Z-ZZ-Wechselwirkung beschrieben, ähnlich dem durch Quantenglühen gelösten Ising-Modell.

Betrachten Sie q (0) ―― 2 * q (1) ―― 3 * q (0) * q (1) als einfaches QUBO. Sei "q (0)" und "q (1)" die Quantenbits, und wenn einer der Werte 0 und 1 genommen wird, wird diese Kombination verwendet, um diese Gleichung zu minimieren. Wenn es 2 Variablen sind, können Sie es von Hand schlagen,

q(0) q(1) q(0) - 2 * q(1) - 3 * q(0) * q(1)
0 0 0 - 20 - 30*0 = 0
1 0 1 - 20 - 31*0 = 1
0 1 0 - 21 - 30*1 = -2
1 1 1 - 21 - 31*1 = -4

Daher wird der Minimalwert bei (1, 1) angenommen. Um danach zu fragen

from blueqat.pauli import qubo_bit as q
from blueqat.vqe import Vqe, QaoaAnsatz

h = q(0) - 2 * q(1) - 3 * q(0) * q(1)

ansatz = QaoaAnsatz(h, 4) #Das zweite Argument ist, um wie viel die Parameter und Schaltungen erhöht werden sollen. Je mehr Sie haben, desto höher ist die Wahrscheinlichkeit des Lösens, aber das Lösen braucht Zeit
runner = Vqe(ansatz)
result = runner.run()
print(result.most_common())

Und das Ergebnis ist

(((1, 1), 0.944590105656669),)

Und (1, 1) wurde mit einer Wahrscheinlichkeit von 94% oder mehr erhalten.

Lesen Sie die Quelle

qubo_bit Lassen Sie die Dokumentzeichenfolge weg. qubo_bit ist einfach so.

def qubo_bit(n):
    return 0.5 - 0.5*Z[n]

Dies ist eine Umschreibung dessen, was in den Bits von QUBO ($ q_i \ in \ {0, 1 \} ) in das aufsteigende Modell ( \ sigma_i \ in \ {\ pm 1 \} $) geschrieben wurde. Ich bin nur da. Es wird so berechnet, dass $ \ sigma_i = 1 $ ist, wenn $ q_i = 0 $ und $ \ sigma_i = -1 $, wenn $ q_i = 1 $.

Z ist in blueqat.pauli als chaotisch definiert, aber wenn es für VQE oder QAOA verwendet wird,

Wird verwendet. Ebenfalls,

Es ist eine Beziehung geworden.

Die Zeitentwicklung ist eine sehr wichtige Berechnung in VQE und QAOA. Eigentlich würde ich mich freuen, wenn ich die zeitliche Entwicklung von Hamiltonian $ \ hat H $ schreiben könnte, also würde ich gerne den Typ "Ausdruck" im Laufe der Zeit entwickeln, aber es ist im Allgemeinen schwierig, ihn mit einer Kombination von Toren zu schreiben, und normalerweise handelt es sich um eine ungefähre Berechnung durch Suzuki Trotter-Erweiterung usw. Getan werden. Andererseits kann der "Term" -Typ, der nur aus Multiplikation besteht, durch Kombinieren von Gates leicht zeitlich entwickelt werden.

QaoaAnsatz.__init__

Ansatz ist ein deutsches Wort, das auf Japanisch als "vorübergehend" übersetzt zu werden scheint, aber es ist ein Kandidat für $ \ boldsymbol {X} $ in $ \ boldsymbol {X} \ cdot \ hat H \ boldsymbol {X} $. In VQE ist es durchaus möglich, auf diese Weise eine Quantenschaltung aufzurufen, die für $ \ boldsymbol {X} $ in Frage kommt. Wie wir später sehen werden, ist die wichtigste Methode in "QaoaAnsatz" "get_circuit ()", die für die Erstellung einer Quantenschaltung aus Parametern verantwortlich ist.

class QaoaAnsatz(AnsatzBase):
    def __init__(self, hamiltonian, step=1, init_circuit=None):
        super().__init__(hamiltonian, step * 2)
        self.hamiltonian = hamiltonian.to_expr().simplify()
        if not self.check_hamiltonian():
            raise ValueError("Hamiltonian terms are not commutable")

        self.step = step
        self.n_qubits = self.hamiltonian.max_n() + 1
        if init_circuit:
            self.init_circuit = init_circuit
            if init_circuit.n_qubits > self.n_qubits:
                self.n_qubits = init_circuit.n_qubits
        else:
            self.init_circuit = Circuit(self.n_qubits).h[:]
        self.init_circuit.make_cache()
        self.time_evolutions = [term.get_time_evolution() for term in self.hamiltonian]

#Von der Elternklasse__init__Hier klicken
class AnsatzBase:
    def __init__(self, hamiltonian, n_params):
        self.hamiltonian = hamiltonian
        self.n_params = n_params
        self.n_qubits = self.hamiltonian.max_n() + 1

Was an die übergeordnete Klasse __init__ übergeben werden soll, ist hamiltonian ($ \ hat H $), die Anzahl der Parameter und die Anzahl der Quantenbits. Die Anzahl der Parameter wird doppelt so hoch wie die Anzahl der Schritte übergeben.

Außerdem muss "hamiltonian" den Typ mit "hamiltonian.to_expr ()" abgleichen. Simplify () "und" simplify () "werden verwendet, um zusätzliche Begriffe zu entfernen oder zu kombinieren.

check_hamiltonian prüft, ob es sich um einen geeigneten Hamiltonian für QAOA handelt.

Als Anfangsschaltung werden, sofern nicht anders angegeben, alle mit "H" multiplizierten Quantenbits übergeben. Dies entspricht dem Beginn des Temperns ab dem Zustand, in dem zuerst ein laterales Magnetfeld angelegt wird, wie es beim Quantenglühen genannt wird.

Wenn Sie make_cache () aufrufen, führen einige Simulatoren bis zu diesem Zeitpunkt Quantenberechnungen durch und speichern die Ergebnisse. Von nun an werde ich die anfängliche Schaltung mit einem mehrmals hinzugefügten Gate verschieben, so dass auf diese Weise unnötige Berechnungen reduziert werden können. self.time_evolutions = [term.get_time_evolution () für term in self.hamiltonian] extrahiert den term type term aus dem Expr type hamiltonian, um eine Funktion für die Zeitentwicklung zu erhalten. Ich werde.

Vqe.__init__

class Vqe:
    def __init__(self, ansatz, minimizer=None, sampler=None):
        self.ansatz = ansatz
        self.minimizer = minimizer or get_scipy_minimizer(
            method="Powell",
            options={"ftol": 5.0e-2, "xtol": 5.0e-2, "maxiter": 1000}
        )
        self.sampler = sampler or non_sampling_sampler
        self._result = None

Es werden drei Objekte benötigt: "Ansatz", "Minimierer" und "Sampler". Wenn Sie "Minimizer" und "Sampler" weglassen, werden die Standardwerte verwendet. minimizer ist eine Funktion zur Minimierung und standardmäßig eine Umhüllung von scipy.optimize.minimize. Sampler ist eine Funktion zum Ausführen der eigentlichen Maschine oder des Simulators und zum Abrufen des Sampling-Ergebnisses. Der Simulator wird standardmäßig verwendet.

Wenn Sie diese in die vorherige Abbildung einfügen, ist dies wie folgt. Ich habe es weggelassen, weil die Figur kompliziert wird, aber ansatz berechnet auch die Energie aus dem Stichprobenergebnis. (Da wir Hamiltonian für die Energieberechnung benötigen, lassen wir das Objekt, das Hamiltonian hat, dies tun.)

vqe_mod.svg.png

Vqe.run()

    def run(self, verbose=False):
        objective = self.ansatz.get_objective(self.sampler)
        if verbose:
            def verbose_objective(objective):
                def f(params):
                    val = objective(params)
                    print("params:", params, "val:", val)
                    return val
                return f
            objective = verbose_objective(objective)
        params = self.minimizer(objective, self.ansatz.n_params)
        c = self.ansatz.get_circuit(params)
        return VqeResult(self, params, c)

if verbose: Das Folgende ist nur ein Chaos für diejenigen, die die Parameter und Energieänderungen sehen wollen, so dass Sie sich nicht zu viele Sorgen machen müssen, wenn Sie es ignorieren

Es ist ein einfacher Prozess.

get_objective

    def get_objective(self, sampler):
        """Get an objective function to be optimized."""
        def objective(params):
            circuit = self.get_circuit(params)
            circuit.make_cache()
            return self.get_energy(circuit, sampler)
        return objective

Die Zielfunktion ist genau so wie in der Abbildung

Es ist ein Fluss geworden.

Für die auf diese Weise erhaltene Zielfunktion werden die Parameter durch "Minimierer" optimiert, so dass sich herausstellt, dass es wirklich wie in der Abbildung gezeigt funktioniert.

Zusammenfassung

VQE und QAOA sind keine komplizierten Algorithmen, solange Sie den Ablauf verstehen können. Dieses Mal habe ich versucht, in die Abbildung zu schreiben, während ich die Quelle gelesen habe, wie es tatsächlich funktioniert.

Bonus: Probleme mit dem aktuellen Blueqat VQE-Modul

Ich habe das Modul so gestaltet, dass die Autorität so weit wie möglich an die Kinderklasse delegiert wird, damit sie so locker wie möglich gekoppelt ist. Der Schlüssel zu VQE ist jedoch "wie man die Parameter optimiert". Insbesondere bei chemischen Berechnungen können Sie die aus der Molekülstruktur erhaltenen Parameter als Anfangswerte verwenden und mit allem, was Sie verwenden können, optimieren. Ich will das tun.

Dies ist eine sehr inkompatible Idee mit der aktuellen Struktur von VQE-Modulen.

Derzeit erhält der Minimierer keine Informationen darüber, welche Funktion optimiert werden soll, außer der Funktion selbst und der Anzahl der Parameter. Der Inhalt der Funktion ist als Black Box optimiert.

Wie kann ich das Modul zur besseren Optimierung wieder zusammenbauen? (Im Moment denke ich daran, das Vqe-Objekt zu erben und es als Methode zu verwenden, anstatt den Minimierer von außen zu übergeben.)

Es gibt auch ein Problem mit der Interaktion mit "Sampler". Im aktuellen "Sampler" wurde angenommen, dass jeder Schaltkreis einzeln ausgeführt wird. Mit IBM Q können jedoch mehrere Schaltkreise gepackt und auf einen Quantencomputer in der Cloud übertragen werden. In IBM Q ist es normal, dass die Wartezeit länger als die Berechnungszeit ist, und das Packen und Ausführen mehrerer Schaltkreise kann viel Zeit sparen. Wie können wir es also schaffen, dass mehrere Schaltkreise zusammen gepackt werden können? (Ich bekomme nur eine Liste der Schaltkreise, führe sie alle zusammen aus und gebe eine Liste der Ergebnisse usw. zurück.)

Blueqat hat viele Sorgen um die Softwareentwicklung und nicht um die beschissene Quantenberechnung. Da es sich um Open Source-Software handelt, suche ich jemanden, der bei der Entwicklung hilft. Wenn Sie von Ihren Fähigkeiten überzeugt sind, lassen Sie es uns bitte wissen.

Recommended Posts

Folgen Sie dem QAOA-Fluss (VQE) auf der Quellcode-Ebene von Blueqat
[Python] Lesen Sie den Quellcode von Flasche Teil 2
[Python] Lesen Sie den Quellcode von Flasche Teil 1
Verfolgen Sie den Kommunikationsfluss der Docker-Bridge-Verbindung mit nftables
Erläutern Sie den Code von Tensorflow_in_ROS
[Python] Lesen Sie den Flask-Quellcode
Anzahl Quellcodezeilen (SLOC)