[PYTHON] Erstellen Sie ein Blueqat-Backend ~ Teil 2

Blueqat-Bibliothek für einfache Quantenprogrammierung

Entwickelt sich. https://github.com/Blueqat/Blueqat

Letztes Mal

Erstellen eines Blueqat-Backends ~ Teil 1 erklärte, wie ein Simulator-Backend erstellt wird, das OpenQ ASM-Eingaben akzeptieren kann. Dieses Mal werde ich erklären, wie ein Backend im allgemeinen Fall erstellt wird, in dem dies nicht der Fall ist.

Wie man alles selbst macht

Sie können mindestens ein Backend erstellen, indem Sie "Backend" erben und die "run" -Methode implementieren. Es implementiert auch die copy -Methode neu, wenn eine Kopie des Backend-Objekts selbst für copy.deepcopy nicht geeignet ist.

Die run Methode hat die Form run (self, Gates, n_qubits, * args, ** kwargs). Gates ist die Liste der Quanten-Gate-Objekte, n_qubits ist die Anzahl der Quantenbits, * args, ** kwargs ist, wenn der Benutzer Circuit (). Run () aufruft Das Argument von "run" wird übergeben.

Wenn Sie dies implementieren, können Sie ein Backend erstellen. Da es jedoch zu viel für den Entwickler bedeutet, haben wir den folgenden Ablauf vorbereitet. Es klingt verwirrend, aber wenn Sie dem Ablauf folgen, kann die Implementierung etwas einfacher sein. Wenn Sie die "run" -Methode erneut implementieren, können Sie auch die von Ihnen vorbereitete verwenden.

Wie Sie auf den von Ihnen vorbereiteten Fluss kommen

Gesamtdurchfluss

Standardmäßig ruft der Aufruf der Methode "run" den folgenden Code auf.

    def _run(self, gates, n_qubits, args, kwargs):
        gates, ctx = self._preprocess_run(gates, n_qubits, args, kwargs)
        self._run_gates(gates, n_qubits, ctx)
        return self._postprocess_run(ctx)

    def _run_gates(self, gates, n_qubits, ctx):
        """Iterate gates and call backend's action for each gates"""
        for gate in gates:
            action = self._get_action(gate)
            if action is not None:
                ctx = action(gate, ctx)
            else:
                ctx = self._run_gates(gate.fallback(n_qubits), n_qubits, ctx)
        return ctx

Was Backend-Entwickler implementieren sollten

--_preprocess_run Methode

ist.

Über ctx

Beachten Sie die Variable mit der Bezeichnung "ctx" hier. Diese Variable ist eine Variable, die den Status vom Anfang bis zum Ende von "run" hält. (Wenn Sie es nicht brauchen, können Sie "None" verwenden, aber ich denke, es gibt wenige Fälle, in denen Sie es überhaupt nicht brauchen.) Da das Backend selbst auch ein gewöhnliches Objekt ist, können Sie ihm einen Status geben, indem Sie "self.foo = ..." usw. setzen. Dies führt jedoch zu Fehlern usw. Verwenden Sie daher so oft wie möglich "ctx".

Als Beispiel dafür, was in ctx gespeichert werden soll

Und so weiter. (Achten Sie darauf, dass Sie es während der Ausführung nicht wissen, es sei denn, Sie belassen die Anzahl der Quantenbits in "ctx".)

Wenn Sie sich den obigen Code ansehen, achten Sie auch auf "ctx"

--Erstelle ein ctx Objekt mit _preprocess_run

Es ist ein Fluss geworden.

Definition der Aktion

Quantenschaltungen werden durch Anordnen von Gates hergestellt. Eine typische Backend-Implementierungsmethode besteht darin, die Gates nacheinander in einer Reihe anzuwenden.

Die Operation des Anlegens eines Gates wird hier als Aktion bezeichnet. Um eine Aktion zu implementieren, fügen Sie einfach eine Methode hinzu:

def gate_{Torname}(self, gate, ctx):
    #Etwas umgesetzt
    return ctx

Machen.

Als Merkmal von Blueqat gab es eine Slice-Notation wie "Circuit (). H [:]", aber es gibt auch eine Methode zum Trennen der Slice-Notation "für idx in gate.target_iter (Anzahl der Bits) Wenn Sie möchten, können Sie den Index von 1 Quantenbitgatter erhalten. Außerdem sollte der Index von 2 Quantenbitgattern wie CNOT "für c, t in gate.control_target_iter (Anzahl der Quantenbits)" sein. Die Anzahl der Quantenbits wird hier benötigt, um die Anzahl der Quantenbits zu kennen, die bei Verwendung von "Circuit (). H [:]" angewendet werden sollen.

Aktion, die definiert werden muss

Nicht alle Tore müssen implementiert werden. Zum Beispiel können T-Gatter und S-Gatter hergestellt werden, wenn es ein rotierendes Z-Gatter (RZ) gibt. Wenn es auf der Blueqat-Seite nicht implementiert ist, achten Sie darauf, stattdessen ein anderes Gatter zu verwenden. Ich bin.

Wenn es kein alternatives Gate gibt, ist es ein Fehler, wenn es verwendet wird, aber es ist kein Fehler, wenn es nicht verwendet wird, sodass Sie ein Backend erstellen können, das nur einige Gates unterstützt. (Wenn Sie beispielsweise nur X-Gatter, CX-Gatter und CCX-Gatter implementieren, können Sie ein Backend erstellen, das auf klassische Logikschaltungen spezialisiert ist. Sie können es mit nur einer Bitoperation implementieren, sodass Sie etwas erstellen können, das mit hoher Geschwindigkeit arbeitet.)

Gates, die implementiert werden müssen, können in Zukunft, aber derzeit, aussortiert werden Die Messungen sind X, Y, Z, H, CZ, CX, RX, RY, RZ, CCZ, U3. (Maßnahmen definieren Aktionen genauso wie Tore.)

Siehe Implementierungsbeispiel

Ein etwas ungewöhnliches Backend ist QasmOutputBackend. Dies ist kein Simulator, sondern ein Backend für die Konvertierung der Blueqat-Quantenschaltungen in OpenQ ASM.

ctx enthält eine Liste von OpenQASM-Zeilen und die Anzahl von Quantenbits. Außerdem fügt jede Aktion der Liste eine Zeile hinzu.

Klicken Sie hier für den gesamten Code.

class QasmOutputBackend(Backend):
    """Backend for OpenQASM output."""
    def _preprocess_run(self, gates, n_qubits, args, kwargs):
        def _parse_run_args(output_prologue=True, **_kwargs):
            return { 'output_prologue': output_prologue }

        args = _parse_run_args(*args, **kwargs)
        if args['output_prologue']:
            qasmlist = [
                "OPENQASM 2.0;",
                'include "qelib1.inc";',
                f"qreg q[{n_qubits}];",
                f"creg c[{n_qubits}];",
            ]
        else:
            qasmlist = []
        return gates, (qasmlist, n_qubits)

    def _postprocess_run(self, ctx):
        return "\n".join(ctx[0])

    def _one_qubit_gate_noargs(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername} q[{idx}];")
        return ctx

    gate_x = _one_qubit_gate_noargs
    gate_y = _one_qubit_gate_noargs
    gate_z = _one_qubit_gate_noargs
    gate_h = _one_qubit_gate_noargs
    gate_t = _one_qubit_gate_noargs
    gate_s = _one_qubit_gate_noargs

    def _two_qubit_gate_noargs(self, gate, ctx):
        for control, target in gate.control_target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername} q[{control}],q[{target}];")
        return ctx

    gate_cz = _two_qubit_gate_noargs
    gate_cx = _two_qubit_gate_noargs
    gate_cy = _two_qubit_gate_noargs
    gate_ch = _two_qubit_gate_noargs
    gate_swap = _two_qubit_gate_noargs

    def _one_qubit_gate_args_theta(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.theta}) q[{idx}];")
        return ctx

    gate_rx = _one_qubit_gate_args_theta
    gate_ry = _one_qubit_gate_args_theta
    gate_rz = _one_qubit_gate_args_theta

    def gate_i(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"id q[{idx}];")
        return ctx

    def gate_u1(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.lambd}) q[{idx}];")
        return ctx

    def gate_u2(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.phi},{gate.lambd}) q[{idx}];")
        return ctx

    def gate_u3(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.theta},{gate.phi},{gate.lambd}) q[{idx}];")
        return ctx

    def gate_cu1(self, gate, ctx):
        for c, t in gate.control_target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.lambd}) q[{c}],q[{t}];")
        return ctx

    def gate_cu2(self, gate, ctx):
        for c, t in gate.control_target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.phi},{gate.lambd}) q[{c}],q[{t}];")
        return ctx

    def gate_cu3(self, gate, ctx):
        for c, t in gate.control_target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.theta},{gate.phi},{gate.lambd}) q[{c}],q[{t}];")
        return ctx

    def _three_qubit_gate_noargs(self, gate, ctx):
        c0, c1, t = gate.targets
        ctx[0].append(f"{gate.lowername} q[{c0}],q[{c1}],q[{t}];")
        return ctx

    gate_ccx = _three_qubit_gate_noargs
    gate_cswap = _three_qubit_gate_noargs

    def gate_measure(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"measure q[{idx}] -> c[{idx}];")
        return ctx

Siehe _preprocess_run

    def _preprocess_run(self, gates, n_qubits, args, kwargs):
        def _parse_run_args(output_prologue=True, **_kwargs):
            return { 'output_prologue': output_prologue }

        args = _parse_run_args(*args, **kwargs)
        if args['output_prologue']:
            qasmlist = [
                "OPENQASM 2.0;",
                'include "qelib1.inc";',
                f"qreg q[{n_qubits}];",
                f"creg c[{n_qubits}];",
            ]
        else:
            qasmlist = []
        return gates, (qasmlist, n_qubits)

Das erste, was wir tun, ist die Analyse von Optionen.

Da es mit der Option output_prologue wie Circuit () ausgeführt werden kann. Run (backend = 'qasm_output', output_prologue = False) wird die Option analysiert. Diese Option ist standardmäßig True, wird jedoch am Anfang von OpenQ ASM hinzugefügt, wenn False angegeben wird.

OPENQASM 2.0;
include "qelib1.inc";
qreg q[Anzahl der Bits];
creg c[Anzahl der Bits];

Wurde weggelassen.

Als nächstes ist ctx eine Liste von OpenQASM-Zeilen und ein Tupel von Quantenbits.

Es gibt Gates und ctx zurück, aber Gates gibt nur das zurück, was als Argument übergeben wurde. Ich habe mich entschieden, Gates mit _preprocess_run zurückzugeben, weil ich die Gate-Spalte für die Optimierung usw. manipulieren wollte. Wenn dies jedoch nicht besonders erforderlich ist, wird das empfangene Argument so zurückgegeben, wie es ist.

Siehe Aktion

    def _one_qubit_gate_noargs(self, gate, ctx):
        for idx in gate.target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername} q[{idx}];")
        return ctx

    gate_x = _one_qubit_gate_noargs
    gate_y = _one_qubit_gate_noargs
    gate_z = _one_qubit_gate_noargs

    #Ausgelassen, weil es viele gibt

    def gate_cu3(self, gate, ctx):
        for c, t in gate.control_target_iter(ctx[1]):
            ctx[0].append(f"{gate.lowername}({gate.theta},{gate.phi},{gate.lambd}) q[{c}],q[{t}];")
        return ctx

Ich werde es so machen. Da es schwierig ist, x-, y- und z-Tore nacheinander herzustellen, trage ich sie seitwärts. Wenn Sie es nicht seitlich tragen können, implementieren Sie es vorsichtig wie "gate_cu3". Was wir tun ist, dass "ctx" war "([Liste der Zeilen], Anzahl der Quantenbits)", also fügen Sie der Liste der Zeilen mit "ctx [0] .append (...)" eine neue Zeile hinzu Ich mache es einfach.

Siehe _postprocess_run

    def _postprocess_run(self, ctx):
        return "\n".join(ctx[0])

Es wird einfach eine Liste von Zeilen als durch Zeilenumbrüche getrennte Zeichenfolge zurückgegeben. Dieses Ergebnis ist das Ergebnis von "run".

Zusammenfassung

Beim letzten Mal haben wir uns die Backend-Implementierungsmethode für Verarbeitungssysteme angesehen, die OpenQ ASM lesen können. Diesmal haben wir uns jedoch die allgemeinere Backend-Implementierungsmethode angesehen.

Bei Blueqat möchten wir uns auf der Bibliotheksseite so weit wie möglich darum kümmern und Entwicklern und Benutzern ermöglichen, das zu tun, was sie wollen. Außerdem können Sie auf einfache Weise ein Backend erstellen, indem Sie auf den von Blueqat bereitgestellten Mechanismus zurückgreifen. Sie können und Sie können sogar die vollständige "Run" -Methode implementieren, ohne an Bord zu kommen.

Jeder kann das Backend selbst erstellen und Sie können sogar Ihren eigenen Simulator mit der Blueqat-Oberfläche verwenden. Jeder, bitte versuchen Sie das Backend zu implementieren.

Recommended Posts

Erstellen Sie ein Blueqat-Backend ~ Teil 1
Erstellen Sie ein Blueqat-Backend ~ Teil 2
Lassen Sie uns ein Backend-Plug-In für Errbot erstellen
Lass uns ein Squashspiel machen
Machen Sie einen Funktionsdekorateur
Erstellen Sie eine Distanzmatrix
Ich mache ein Passwort!
Machen Sie einen Nyan-Knopf
Mach ein Spiel im Tetris-Stil!
Erstellen Sie einen Base64-Decoder
Wie man ein Schießspiel mit toio macht (Teil 1)
Machen wir einen Discord Bot.
Erstellen Sie mit QGIS Part 2 ein tky2jgd-Plug-In ohne praktische Anwendbarkeit
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit Teil 2-
Erstellen eines tky2jgd-Plug-Ins ohne praktische Anwendbarkeit mit QGIS Teil 1
[Django] Erstellen Sie ein Pulldown-Menü
Machen Sie einen LINE BOT (Chat)
Erstellen Sie ein Lesezeichen in Python
Machen Sie eine Lotterie mit Python
Machen Sie Responder zu einem Daemon (Dienst)
Machen Sie ein Feuer mit kdeplot
Erstellen Sie einen Berechnungsbohrdruck
Lassen Sie uns eine WEB-Anwendung für das Telefonbuch mit Flasche Teil 1 erstellen
Lassen Sie uns eine WEB-Anwendung für das Telefonbuch mit Flasche Teil 2 erstellen
Machen Sie ein Thermometer mit Raspberry Pi und machen Sie es im Browser Teil 4 sichtbar
So führen Sie einen Komponententest durch Teil 1 Entwurfsmuster zur Einführung
Lassen Sie uns eine WEB-Anwendung für das Telefonbuch mit Flasche Teil 3 erstellen
Lassen Sie uns eine WEB-Anwendung für das Telefonbuch mit Flasche Teil 4 erstellen
Machen wir eine Remote-Rumba [Hardware]
Wie erstelle ich eine japanisch-englische Übersetzung?
Machen Sie eine Santa-Kennung aus einem Santa-Bild
Spiele mit einer Schildkröte mit Schildkrötengrafiken (Teil 1)
Lassen Sie uns eine Remote-Rumba erstellen [Software]
Machen Sie eine Tweet-Box für Pepper
Lassen Sie uns eine GUI mit Python erstellen.
Machen Sie einen Sound mit Jupyter Notebook
Machen wir einen Spot Sale Service 2
Erstellen Sie mit TensorFlow eine Gesichtserkennung
Wie man einen lockeren Bot macht
Machen wir einen Blockbruch mit wxPython
Machen wir einen Spot Sale Service 1
Wie erstelle ich einen Crawler?
So erstellen Sie eine rekursive Funktion
Machen Sie die C-Kompilierung etwas einfacher
Python / Machen Sie ein Diktat aus einer Liste.
[Python] Machen Sie die Funktion zu einer Lambda-Funktion
Erstellen Sie ein Empfehlungssystem mit Python
[Blender] So erstellen Sie ein Blender-Plug-In
Machen Sie einen Filter mit einer Django-Vorlage
[LINE Bot] Ich bin ein Ranger! Teil 2
Lassen Sie uns ein Diagramm mit Python erstellen! !!
Machen wir mit xCAT einen Spacon
Wie erstelle ich einen Crawler?
Erstellen Sie mit PySide einen Modelliterator
Machen Sie eine schöne Grafik mit Plotly
Machen Sie einen Vorhanggenerator mit Blender