[PYTHON] Grundlagen der Quanteninformationstheorie: Universelle Quantenberechnung durch Oberflächencode (1)

\def\bra#1{\mathinner{\left\langle{#1}\right|}} \def\ket#1{\mathinner{\left|{#1}\right\rangle}} \def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}

Einführung

In Vorheriger Artikel wird Logik erstellt, indem Fehler (Bereiche ohne Operatoren) in den Oberflächenoperatoren und Scheitelpunktoperatoren erstellt werden, die auf dem ebenen Gitter verteilt sind. Wir haben gesehen, dass Quantenbits und logische $ X $ - und logische $ Z $ -Operatoren definiert werden können und dass CNOT-Operationen erreicht werden können, indem Fehler umeinander verschoben werden. Diese CNOT-Operation ist jedoch tatsächlich unvollständig, um ein Element der universellen Quantenberechnung zu sein. Der Grund wird später erklärt. In diesem Artikel werde ich untersuchen, wie ein vollständiger CNOT erreicht werden kann. Um eine universelle Quantenberechnung zu realisieren, wäre es gut, wenn wir eine beliebige einheitliche Operation von 1 Quantenbit vorbereiten könnten, aber das werden wir beim nächsten Mal tun. Nachdem Sie ein allgemeines Verständnis haben, verwenden Sie den Quantenberechnungssimulator qlazy, um dessen Funktion zu überprüfen.

Die folgenden Dokumente wurden als Referenz verwendet.

  1. Koshiba, Morimae, Fujii "Quantenberechnung basierend auf Beobachtung" Corona (2017)
  2. K.Fujii,"Quantum Computation with Topological Codes - from qubit to topological fault-tolerance",arXiv:1504.01444v1 [quant-ph] 7 Apr 2015
  3. Fujii "Einführung in die Quantenberechnung" (2012)
  4. Neilsen Chan "Quantencomputer und Quantenkommunikation II" (2005)

Erklärung der Theorie

Topologische Darstellung von Flechtoperationen

Es gibt ein Thema, an das ich denken möchte, bevor ich zum Hauptthema komme. In Vorheriger Artikel wurde festgestellt, dass Flechten die logische Operation von 2 Quantenbits ausdrücken kann, aber das erklärende Diagramm, das den Defekt in der Ebene bewegt, ist fehlerhaft. Es ist äußerst schwierig zu verstehen, welche Art von topologischer Wicklung realisiert wird und welcher logischen Operation sie entspricht, wenn die Zeit geändert wird. Daher werden wir ein schematisches Diagramm einführen, um das Verständnis der topologischen Merkmale in 3D-Raum und -Zeit zu erleichtern.

Betrachten Sie zunächst die Bewegung von Defekten vom p-Typ. Angenommen, Sie haben ein Defektpaar vom p-Typ, wie in der folgenden Abbildung links gezeigt. Durch Hinzufügen einer Kette von $ X $ -Operatoren, die diesen Fehler mit der Quelle verbinden, konnten wir das logische $ \ ket {+} $ ausdrücken, das der eindeutige Status des logischen $ X $ ist (oben in der Abbildung unten). Dieser Zustand wird durch das Symbol $ \ ket {+} ^ {p} $ dargestellt, was die durch den p-Typ-Defekt erzeugte Logik $ \ ket {+} $ bedeutet (Index L wie in der Abbildung gezeigt). Ich möchte auf der rechten Seite des Kets schreiben, aber aus irgendeinem Grund wird es nicht gut gerendert. Es tut mir leid, bitte denken Sie, dass es ein L gibt, und so weiter. Dies ist schematisch oben rechts in der Abbildung unten dargestellt. Hier repräsentiert die vertikale Richtung die räumliche Position (denken Sie daran, eine zweidimensionale Ebene auf eine Dimension abzubilden), und die horizontale Richtung repräsentiert die Zeitachse. Dann wird die zeitliche Variation der $ X $ -Kette durch die gekrümmte Oberfläche in diesem Raum und in dieser Zeit dargestellt. Stellen Sie sich vor, die Kette, die die Defekte verbindet, bewegt sich entlang der Zeitachse und zeichnet eine bandartige Flugbahn in Raum und Zeit. Andererseits kann $ \ ket {0} ^ {p} $ ausgedrückt werden, indem dem Generator eine Schleife des Operators $ Z $ hinzugefügt wird, die einen der Fehler im Fehlerpaar umgibt (untere Mitte der folgenden Abbildung). Dies ist in der folgenden Abbildung unten rechts schematisch dargestellt. Die zeitliche Variation der Schleife dieses $ Z $ -Operators wird auch durch die gekrümmte Oberfläche auf diesem raumzeitlichen Raum dargestellt. Im Gegensatz zu früher bewegt sich die den Defekt umgebende Schleife (wie ein Gummiring) entlang der Zeitachse, sodass die Flugbahn zu einer gekrümmten Oberfläche wie ein Rohr wird.

fig01.png

Die Erzeugung und Messung von Fehlerpaaren kann auch in diesem schematischen Diagramm dargestellt werden. Ein p-Typ-Defektpaar könnte durch Messen von $ X $ an einem Punkt (Quantenbit) im Vakuumzustand erzeugt werden. Dies kann schematisch so dargestellt werden, dass eine Messung irgendwo aus einem leeren Vakuum durchgeführt wird und ein Paar von Defekten erzeugt wird. Der auf diese Weise erzeugte Zustand ist der eindeutige Zustand der $ X $ -Kette, der die beiden Fehler verbindet. Durch Messen dieser $ X $ -Kette kann dann der Wert als logisches Bit bestimmt werden, aber wir werden die Operation in einem Diagramm darstellen, in dem die Fehler gepaart sind [^ 1](siehe die folgende Abbildung). ..

[^ 1]: Sie haben vielleicht den Eindruck, dass das Fehlerpaar hier verschwindet, aber ich denke, dass der Eigenwert des logischen Quantenbits nur auf +1 oder -1 festgelegt ist und nicht in den Vakuumzustand zurückkehrt. (Vielleicht). Um in den Vakuumzustand zurückzukehren, müssen Sie meines Erachtens einen der beiden Oberflächenoperatoren (Schleife des $ Z $ -Operators) mit zwei nebeneinander liegenden Fehlern messen (bitte darauf hinweisen, wenn dies falsch ist). Der $ Z $ -Operator, der um eines der Fehlerpaare vom p-Typ platziert ist, kann den Eigenzustand des logischen $ Z $ -Operators darstellen, aber selbst wenn dieser gemessen wird, verschwindet der Fehler nicht. Nein ich denke).

fig02.png

Betrachten Sie als nächstes den Defekt vom Typ d. Das Bild ist genau das gleiche wie der Typ p, außer dass die Positionen des Operators $ X $ und des Operators $ Z $ umgekehrt sind, sodass es reibungslos verläuft. Angenommen, Sie haben ein Defektpaar vom Typ d, wie in der folgenden Abbildung links gezeigt. Durch Hinzufügen einer Kette von $ Z $ -Operatoren, die diesen Fehler mit dem Generator verbinden, kann $ \ ket {0} ^ {d} $ dargestellt werden (oben in der Abbildung unten), und diese Zeitänderung ist schematisch oben rechts in der Abbildung unten dargestellt. Es wird durch eine gekrümmte Oberfläche (Band) wie dargestellt. Zusätzlich kann $ \ ket {+} ^ {d} $ durch eine Schleife des $ X $ -Operators dargestellt werden, die eines dieser Fehlerpaare umgibt (unten in der Abbildung unten), und diese Zeitänderung ist in der folgenden Abbildung rechts schematisch dargestellt. Es wird durch eine gekrümmte Oberfläche (Rohr) dargestellt, wie unten gezeigt.

fig03.png

Die Erzeugung von Defektpaaren vom d-Typ kann ausgedrückt werden, indem das Vakuum durch $ Z $ -Messung mit dem Eigenzustand $ \ ket {0} ^ {d} $ der Logik $ Z $ gepaart wird. Schließlich kann der Wert als logisches Bit durch Messen der $ Z $ -Kette erhalten werden. Diese Operation wird jedoch durch ein Diagramm dargestellt, in dem das Fehlerpaar verschwindet (siehe Abbildung unten).

fig04.png

Letzter CNOT

Verwenden wir nun das im vorherigen Abschnitt eingeführte schematische Diagramm, um die in Vorheriger Artikel realisierte CNOT-Operation darzustellen. Die folgende Abbildung zeigt, wie ein Paar von Fehlern vom Typ p einen eindeutigen Zustand von logischem $ X $ $ \ ket {+} ^ {p} $ erzeugt und einen der Fehler um einen Fehler vom Typ d umschließt [^] 2]. Die Kette, die die p-Typ-Defekte verbindet, wickelt sich um die d-Typ-Defekte, und ein neues Rohr (logischer $ X $ -Operator) erscheint in den d-Typ-Defekten, und das ursprüngliche p-Typ-Band behält seine ursprüngliche Form bei. das ist,

[^ 2]: Dies ist ein Zitat aus der Abbildung in Referenz 3. Ich habe einige in anderen Teilen dieses Artikels zitiert. Diese Folie von Professor Fujii ist mit vielen topologischen Diagrammen leicht zu verstehen. es wird empfohlen!

X_1 \otimes I_2 \rightarrow X_1 \otimes X_2  \tag{1}

Es entspricht der logischen Operation. Woher weißt du das? Stellen Sie sich den d-förmigen Defekt unten als zwei Stäbe vor. Darüber befindet sich eine Kette, die einen p-förmigen Defekt darstellt, der sich von links nach rechts bewegt und dessen Unterkante sich um die untere Stange wickelt. Dann können Sie sich vorstellen, dass ein Ring aus einer Kette neu geboren wurde [^ 3].

[^ 3]: Ich denke, es wäre einfacher zu verstehen, wenn Sie diese Situation mit einem Video erklären könnten, aber es tut mir leid, ich habe nicht den Hintergrund, um Videos zu machen. Bitte geben Sie Ihr Bestes und machen Sie ein Video in Ihrem Kopf.

fig05.png

Die folgende Abbildung zeigt den gleichen Vorgang mit unterschiedlichen Anfangszuständen. Hier wird der Eigenzustand $ \ ket {0} ^ {d} $ des logischen $ Z $ -Operators mit dem Fehlerpaar vom d-Typ erzeugt, und einer der Fehler vom p-Typ wird um den Fehler vom d-Typ gewickelt. .. Sie können sehen, dass die Kette, die die Defekte vom Typ d verbindet, durch die Defekte vom Typ p aufgewickelt wird und ein neues Rohr (logischer $ Z $ -Operator) in den Defekten vom Typ p erscheint. Die ursprüngliche d-förmige Oberfläche behält ihre ursprüngliche Form. das ist,

I_1 \otimes Z_2 \rightarrow Z_1 \otimes Z_2  \tag{2}

Es entspricht der logischen Operation. Die Operation ist die gleiche wie zuvor, aber dieses Mal gibt es einen dünnen Film zwischen den beiden Stäben, die den Defekt vom d-Typ darstellen, und einer der oberen Defekte vom p-Typ wickelt sich um den Stab vom d-Typ und um einen der Defekte vom p-Typ. Es ist ein Bild, dass ein neuer Kreis geboren wird.

fig06.png

Im vorherigen Artikel sagte er, dass CNOT damit realisiert wurde. Wenn Sie genau hinschauen, ist die Kontrollseite jedoch ein p-Typ-Defekt und die Zielseite ein d-Typ-Defekt. CNOT kann ohne diese Kombination nicht durchgeführt werden. Also, was ist falsch? Es scheint gesagt zu werden, aber es ist nicht sehr gut. Zum Beispiel

fig07.png

Es sind nur solche CNOT-Kombinationen möglich. Das SWAP-Gatter ist eine typische Einheitsoperation für 2 Quanten.

fig08.png

Wie Sie durch Schreiben wie sehen können, ist es nicht möglich, wenn der p-Typ-Defekt nur auf der Steuerseite der CNOT-Operation verwendet werden kann. Im Allgemeinen können Einheitsoperationen für jeden N-Quantenbitzustand in das Produkt aus 1 Quantenbit-Einheitsoperation und 2 Quantenbit-CNOT-Operationen zerlegt werden (Referenz 4). (Siehe jp / book / 9784274200083 /)), aber wenn es eine Einschränkung gibt, dass nur bestimmte Quantenbits als Steuerbits verwendet werden können (oder nur bestimmte Quantenbits als Zielbits verwendet werden können), ist eine solche Zerlegung unmöglich. Mit anderen Worten, um eine universelle Quantenberechnung unter Verwendung des Oberflächencodes von Defektpaaren zu realisieren, ist es notwendig, eine CNOT-Operation zu realisieren, bei der mindestens das Steuerbit und das Zielbit p-Typ-Defekte sind.

Dieser CNOT

Wie können wir dann eine solche CNOT-Operation realisieren, dass sowohl die Steuerseite als auch die Zielseite p-Typ-Defekte sind? Um ehrlich zu sein, bin ich mir nicht sicher, wie es abgeleitet wurde, also sage ich nur die Antwort in der Referenz. Die Antwort besteht darin, das folgende Ersatzschaltbild des CNOT-Betriebs zu betrachten [^ 4].

[^ 4]: Das ist sicherlich CNOT, ist das okay? Ich denke, es ist leicht zu verstehen, wenn Sie über Eingabe und Ausgabe in einem Stabilisatorformat nachdenken. Das heißt, wenn die Eingabe $ X \ otimes I $ ist, ist die Ausgabe $ X \ otimes X $, oder wenn die Eingabe $ I \ otimes Z $ ist, ist die Ausgabe $ Z \ otimes Z . Wenn Sie usw. überprüfen, können Sie sehen, dass es sich sicherlich um CNOT handelt. Es gibt jedoch eine Einschränkung. Wenn der gemessene Wert beim Verschwinden des 4. p-Typ-Defekts -1 ist, werden das 1. und 3. logische Quantenbit invertiert ( \ ket {+} $ wird von $ in $ \ ket {-} $ konvertiert Sie müssen \ ket {-} $ nach $ \ ket {+} $ drehen. Sie können es durch sorgfältige Berechnung des Stabilisatorformats sehen.

fig09.png

Dies ist eine gewöhnliche Quantenschaltung, die kein Oberflächencode ist, aber das erste, dritte und vierte Quantenbit von oben werden als Steuerbits verwendet, und das zweite Quantenbit wird als Zielbit verwendet. Es ist in Form. Wenn Sie dies also wie im Oberflächencode nachdrucken und die Fehler vom 1., 3. und 4. p-Typ sowie die 2. Fehler vom d-Typ wie unten gezeigt ausführen, verwendet CNOT nur Fehler vom p-Typ Kann realisiert werden.

fig10.png

Wenn Sie in das zuvor erläuterte schematische Diagramm schreiben, sieht es wie in der Abbildung links aus. Die Abbildung rechts unten zeigt einen einfachen Ausdruck, so dass die Werte topologisch gleich sind und die Wicklungsstruktur unverändert bleibt.

fig11.png

Da die räumliche Dimension ursprünglich zweidimensional war, wenn die Topologie in dreidimensionaler Raumzeit genau ausgedrückt wird,

fig12.png

Es wird sein. Wie ist das? Es ist ein mysteriöses objektähnliches Objekt der zeitgenössischen Kunst erschienen, das die CNOT-Operation im Oberflächencode unter Verwendung von Defekten darstellt.

Funktionsprüfung

Verwenden wir nun den Quantenberechnungssimulator qlazy, um zu sehen, ob damit eine CNOT-Operation wirklich realisiert werden kann. Da das Flechten komplizierter ist als beim letzten Mal, ist die Größe des zu erstellenden ebenen Gitters um diesen Betrag größer. Wenn Sie jedoch das Stabilisatorformat verwenden, ist dies kein Problem, da Sie nur die Clifford-Berechnung und -Messung benötigen.

Entwerfen Sie zunächst, welche Art von Flechten durchgeführt werden soll. Solange sich der Defekt und seine Bewegung in der oben erläuterten Topologie befinden, sollte es möglich sein, eine Entscheidung zu treffen. Daher habe ich die Bewegung vorerst wie in der folgenden Abbildung gezeigt versucht.

fig13.png

fig14.png

Erstellen Sie zunächst in (1) einen Vakuumzustand (verteilen Sie den Oberflächenoperator und den Scheitelpunktoperator über das gesamte Gitter).

Generieren Sie 4 Fehlerpaare in (2) (messen Sie die entsprechende Stelle und verschieben Sie den Fehler). Nennen Sie die Quantenbitnummern 0, 1, 2 und 3 oben im oben gezeigten CNOT-Schaltplan [^ 5] und ordnen Sie sie wie in (2) gezeigt an. Der 0., 2. und 3. sind Fehlerpaare vom p-Typ und befinden sich im Eigenzustand von logischen $ X $, und die ersten sind Fehlerpaare vom d-Typ und befinden sich im Eigenzustand von logischen $ Z $. Sie können einen eindeutigen Status von $ + 1 $ vorbereiten, indem Sie je nach Messwert den logischen Operator $ Z $ oder den logischen Operator $ X $ anwenden.

[^ 5]: Aufgrund der Bequemlichkeit der Programmimplementierung beginnt die Quantenbitnummer am 0 .. Dies ist in diesem Blog fast der Fall, da es einfacher ist, die Theorie mit dem ersten zu erklären, aber in den meisten Programmiersprachen beginnt der Index des Arrays mit dem 0. (FORTRAN hat sicherlich den Index des Arrays 1). Ich denke es war von der zweiten). Manchmal bin ich verwirrt, aber ich muss mich daran gewöhnen.

Flechten Sie den Defekt in (3). Wickeln Sie eines der 0. Fehlerpaare um eines der 1. Fehlerpaare und eines des 2. und 3. Fehlerpaars um das andere des 1. Fehlerpaars.

Messen Sie in (4) das erste Fehlerpaar für $ Z $ und das dritte Fehlerpaar für $ X $.

Dies sollte CNOT implementieren. Wenn Sie die Eingabe / Ausgabe-Beziehung basierend auf $ X $ ausdrücken möchten

Eingangsseitige Steuerung und Ziel Ausgangsseitige Steuerung und Ziel
\ket{++} \ket{++}
\ket{+-} \ket{-+}
\ket{+-} \ket{--}
\ket{--} \ket{+-}

Es wird [^ 6]. In (2) oben wurde $ \ ket {+} $ als Steuerbit (0. Quantenbit) auf der Eingangsseite und $ \ ket {+} $ als Zielbit (3. Quantenbit) auf der Eingangsseite vorbereitet. Aus der ersten Zeile dieser Tabelle ist dann das Steuerbit (0. Quantenbit) auf der Ausgangsseite $ \ ket {+} $ und das Zielbit (2. Quantenbit) auf der Ausgangsseite ist $ \ ket {+. } Es wird $ sein. Mit anderen Worten, wenn Sie das 0. und 2. Quantenbit für $ X $ messen, sollten Sie $ (+ 1, + 1) $ mit einer Wahrscheinlichkeit von $ 100 % $ beobachten. Bereiten Sie außerdem $ \ ket {+} $ als Steuerbit auf der Eingabeseite vor und wenden Sie den logischen Operator $ Z $ auf das Zielbit $ \ ket {+} $ auf der Eingabeseite an, um $ \ ket {-} $ zu setzen. Wenn vorbereitet, sind in der zweiten Zeile dieser Tabelle die Steuer- und Zielbits auf der Ausgabeseite $ \ ket {-} $ und $ \ ket {+} $. Mit anderen Worten, wenn Sie das 0. und 2. Quantenbit für $ X $ messen, sollten Sie $ (-1, + 1) $ mit einer Wahrscheinlichkeit von $ 100 % $ beobachten. Ebenso können Sie die Eingabe / Ausgabe-Beziehungen der 3. und 4. Zeile dieser Tabelle überprüfen.

[^ 6]: Ist das okay? Wenn Sie in einem Stabilisatorformat darüber nachdenken, wissen Sie es sofort. Die erste Zeile der Tabelle ist $ \ <XI, IX > \ rightarrow \ <XX, IX > = \ <XI, IX > $, die zweite Zeile ist $ \ <XI, -IX > \ rightarrow \ < -XX, IX > = \ <-XI, IX > $ usw.

Implementierung

Hier ist der gesamte Python-Code.

from collections import Counter
from qlazypy import Stabilizer

XBASE = {'0':'+', '1':'-'}
OBJECT = {'p':'face', 'd':'vertex'}

def get_common_qid(obj_A, obj_B):

    return list(set(obj_A['dat']) & set(obj_B['dat']))

def get_path(pos_A, pos_B):

    path = []

    if pos_A[1] < pos_B[1]: h_list = list(range(pos_A[1], pos_B[1] + 1))
    else: h_list = list(reversed(range(pos_B[1], pos_A[1] + 1)))
    for j in h_list: path.append([pos_A[0], j])

    if pos_A[0] < pos_B[0]: v_list = list(range(pos_A[0] + 1, pos_B[0] + 1))
    else: v_list = list(reversed(range(pos_B[0], pos_A[0])))
    for i in v_list: path.append([i, pos_B[1]])

    return path

def create_lattice(row, col):

    face = [[None]*col for _ in range(row)]
    vertex = [[None]*(col+1) for _ in range(row+1)]

    q_row = 2 * row + 1
    q_col = 2 * col + 1
    q_id = 0
    for i in range(q_row):
        for j in range(q_col):
            if i%2 == 1 and j%2 == 1: # face
                dat = []
                dat.append((i - 1) * q_col + j)  # up
                dat.append((i + 1) * q_col + j)  # down
                dat.append(i * q_col + (j - 1))  # left
                dat.append(i * q_col + (j + 1))  # right
                face[i//2][j//2] = {'anc': q_id, 'dat': dat}

            elif i%2 == 0 and j%2 == 0: # vertex
                dat = []
                if i > 0: dat.append((i - 1) * q_col + j)          # up
                if i < q_row - 1: dat.append((i + 1) * q_col + j)  # down
                if j > 0: dat.append(i * q_col + (j - 1))          # left
                if j < q_col - 1: dat.append(i * q_col + (j + 1))  # right
                vertex[i//2][j//2] = {'anc': q_id, 'dat': dat}
                
            q_id += 1
            
    return {'face': face, 'vertex': vertex}

def initialize(sb, lattice):

    i = 0  # generator id
    for face_list in lattice['face']:
        for face in face_list:
            [sb.set_pauli_op(i, q, 'Z') for q in face['dat']]
            i += 1
            sb.set_pauli_op(i, face['anc'], 'Z')
            i += 1

    for vertex_list in lattice['vertex']:
        for vertex in vertex_list:
            [sb.set_pauli_op(i, q, 'X') for q in vertex['dat']]
            i += 1
            sb.set_pauli_op(i, vertex['anc'], 'Z')
            i += 1

def get_chain(pos_list, dtype, lattice):

    chain = []
    for i in range(1,len(pos_list)):
        pos_A = pos_list[i-1]
        pos_B = pos_list[i]
        chain.append(get_common_qid(lattice[OBJECT[dtype]][pos_A[0]][pos_A[1]],
                                    lattice[OBJECT[dtype]][pos_B[0]][pos_B[1]])[0])
    return chain

def move_defect(sb, pos_A, pos_B, path, dtype, lattice, create=False, annihilate=False):

    obj = OBJECT[dtype]
    if create == True:
        obj_A = lattice[obj][pos_A[0]][pos_A[1]]
        obj_B = lattice[obj][pos_B[0]][pos_B[1]]
        q = get_common_qid(obj_A, obj_B)[0]
        if dtype == 'p':
            md = sb.mx(qid=[q])
            if md.last == '1': [sb.z(i) for i in obj_B['dat']]
        elif dtype == 'd':
            md = sb.m(qid=[q])
            if md.last == '1': [sb.x(i) for i in obj_B['dat']]
        
    chain = get_chain(get_path(pos_A, pos_B), dtype, lattice)
    for i in range(1,len(path)):
        # extend defect
        obj_A = lattice[obj][path[i-1][0]][path[i-1][1]]
        obj_B = lattice[obj][path[i][0]][path[i][1]]
        q = get_common_qid(obj_A, obj_B)[0]
        if dtype == 'p':
            md = sb.mx(qid=[q])
            if md.last == '1': [sb.z(i) for i in obj_B['dat']]
        elif dtype == 'd':
            md = sb.m(qid=[q])
            if md.last == '1': [sb.x(i) for i in obj_B['dat']]
            
        # remove defect
        sb.h(obj_A['anc'])
        if dtype == 'p': [sb.cz(obj_A['anc'], target) for target in obj_A['dat']]
        elif dtype == 'd': [sb.cx(obj_A['anc'], target) for target in obj_A['dat']]
        sb.h(obj_A['anc'])
        md = sb.m(qid=[obj_A['anc']])
        if md.last == '1':
            if dtype == 'p': [sb.x(i) for i in chain]
            elif dtype == 'd': [sb.z(i) for i in chain]
            sb.x(obj_A['anc'])

        chain.append(q)

    if annihilate == True:
        obj_A = lattice[obj][pos_A[0]][pos_A[1]]
        obj_B = lattice[obj][path[-1][0]][path[-1][1]]
        q = get_common_qid(obj_A, obj_B)[0]
        if dtype == 'p': md = sb.mx(qid=[q])
        elif dtype == 'd': md = sb.m(qid=[q])
        return md.last
    
    return None

def measure_logical_X(sb, chain_A, chain_B, shots=1):

    mval_list = []
    for _ in range(shots):
        sb_tmp = sb.clone()
        mval_A = sb_tmp.mx(qid=chain_A).last
        mval_B = sb_tmp.mx(qid=chain_B).last
        mval_A_bin = str(sum([int(s) for s in list(mval_A)])%2)
        mval_B_bin = str(sum([int(s) for s in list(mval_B)])%2)
        mval = (XBASE[mval_A_bin] + XBASE[mval_B_bin])
        mval_list.append(mval)
        sb_tmp.free()
        
    return Counter(mval_list)

def operate_logical_Z(sb, lq, lattice):

    if lq == 0: face = lattice['face'][0][0]
    elif lq == 2: face = lattice['face'][0][7]
    elif lq == 3: face = lattice['face'][6][0]
    [sb.z(q) for q in face['dat']]

def operate_logical_cnot(lq, shots=5):

    # set lattice
    lattice_row, lattice_col = 7, 8
    lattice = create_lattice(lattice_row, lattice_col)

    # make vacuum state
    qubit_num = (2 * lattice_row + 1) * (2 * lattice_col + 1)
    sb = Stabilizer(qubit_num=qubit_num, gene_num=qubit_num+1)
    initialize(sb, lattice)

    # set logical qubit #0
    p0_pos_A, p0_pos_B = [0,0], [0,1]
    p0_path = [[0,1],[0,2]]
    move_defect(sb, p0_pos_A, p0_pos_B, p0_path, 'p', lattice, create=True)
    if lq[0] == '-': operate_logical_Z(sb, 0, lattice)

    # set logical qubit #1
    d1_pos_A, d1_pos_B = [2,5], [3,5]
    d1_path = [[3,5],[4,5],[5,5]]
    move_defect(sb, d1_pos_A, d1_pos_B, d1_path, 'd', lattice, create=True)

    # set logical qubit #2
    p2_pos_A, p2_pos_B = [0,7], [1,7]
    p2_path = [[1,7],[2,7],[3,7]]
    move_defect(sb, p2_pos_A, p2_pos_B, p2_path, 'p', lattice, create=True)

    # set logical qubit #3
    p3_pos_A, p3_pos_B = [6,0], [6,1]
    p3_path = [[6,1],[6,2]]
    move_defect(sb, p3_pos_A, p3_pos_B, p3_path, 'p', lattice, create=True)
    if lq[1] == '-': operate_logical_Z(sb, 3, lattice)

    # braid logical qubit #0
    p0_pos_A, p0_pos_B = [0,0], [0,2]
    p0_path = [[0,2],[1,2],[2,2],[3,2],[3,3],[3,4],[3,5],[3,6],
               [2,6],[1,6],[0,6],[0,5],[0,4],[0,3],[0,2]]
    move_defect(sb, p0_pos_A, p0_pos_B, p0_path, 'p', lattice)
    
    # braid logical qubit #2
    p2_pos_A, p2_pos_B = [0,7], [3,7]
    p2_path = [[3,7],[3,6],[3,5],[3,4],[3,3],[4,3],[5,3],
              [6,3],[6,4],[6,5],[6,6],[6,7],[5,7],[4,7],[3,7]]
    move_defect(sb, p2_pos_A, p2_pos_B, p2_path, 'p', lattice)

    # braid and annihilate logical qubit #3
    p3_pos_A, p3_pos_B = [6,0], [6,2]
    p3_path = [[6,2],[6,3],[6,4],[6,5],[6,6],[5,6],[4,6],[3,6],
               [3,5],[3,4],[3,3],[3,2],[4,2],[5,2],[6,2],[6,1]]
    mval_p = move_defect(sb, p3_pos_A, p3_pos_B, p3_path, 'p', lattice, annihilate=True)

    # braid and annihilate logical qubit #1
    d1_pos_A, d1_pos_B = [2,5], [5,5]
    d1_path = [[5,5],[4,5],[3,5]]
    mval_d = move_defect(sb, d1_pos_A, d1_pos_B, d1_path, 'd', lattice, annihilate=True)

    if mval_p == '1':
        operate_logical_Z(sb, 0, lattice)
        operate_logical_Z(sb, 2, lattice)
    
    # measure logical qubits: #0 and #2
    chain_0 = get_chain(get_path([0,0],[0,2]), 'p', lattice)
    chain_2 = get_chain(get_path([0,7],[3,7]), 'p', lattice)
    freq = measure_logical_X(sb, chain_0, chain_2, shots=shots)
    print("Input('{0:}') == [CNOT] ==> {1:}".format(lq, freq))

    sb.free()

if __name__ == '__main__':

    operate_logical_cnot('++', shots=10)  # --> '++'
    operate_logical_cnot('+-', shots=10)  # --> '--'
    operate_logical_cnot('-+', shots=10)  # --> '-+'
    operate_logical_cnot('--', shots=10)  # --> '+-'

Es ist ziemlich lange her, also werde ich es grob erklären. Die Funktion oper_logical_cnot ist der Hauptteil dieser Zeit. Durch Angabe des Eingabestatus als Zeichenfolge ('++', '+ -', '- +', '-') als erstes Argument und Angabe der Anzahl der Messungen als ganzzahliger Wert im zweiten Argument kann das Messergebnis erhalten werden. Anzeige.

Schauen Sie in die Funktion operation_logical_cnot.

# set lattice
lattice_row, lattice_col = 7, 8
lattice = create_lattice(lattice_row, lattice_col)

Stellen Sie dann die vertikale und horizontale Größe des Gitters auf $ 7 \ mal 8 $ ein, wie in der obigen Abbildung erläutert, und erstellen Sie die Gitterdaten mit der Funktion create_lattice. Dies ist dasselbe wie Vorheriger Artikel, daher werde ich die Erklärung weglassen.

# make vacuum state
qubit_num = (2 * lattice_row + 1) * (2 * lattice_col + 1)
sb = Stabilizer(qubit_num=qubit_num, gene_num=qubit_num+1)
initialize(sb, lattice)

Geben Sie dann die Anzahl der Quantenbits und die Anzahl der Erzeugungsquellen, die dem erzeugten Gitter entsprechen, dem Stabilisatorkonstruktor Stabilizer an, um die Instanz sb zu erzeugen. Verwenden Sie dann die Initialisierungsfunktion, um es in einen Vakuumzustand zu versetzen. Verteilen Sie also die Flächen- und Scheitelpunktoperatoren über das Raster. Einzelheiten finden Sie in der obigen Funktionsdefinition. Ich setze einfach den $ X $ - oder $ Z $ -Operator auf jedes Quantenbit mit der set_pauli_op-Methode von sb.

# set logical qubit #0
p0_pos_A, p0_pos_B = [0,0], [0,1]
p0_path = [[0,1],[0,2]]
move_defect(sb, p0_pos_A, p0_pos_B, p0_path, 'p', lattice, create=True)
if lq[0] == '-': operate_logical_Z(sb, 0, lattice)

Erzeugt das 0. logische Quantenbit. Mit der Funktion move_defect werden die Quantenbits an den Grenzen der Ebenenoperatorkoordinaten [0,0], [0,1] mit $ X $ gemessen, um ein Paar p-Typ-Defekte zu erzeugen, und die Defekte von [0,1] werden erzeugt. Wir bearbeiten, um zu Koordinaten zu gelangen [0,2]. Wenn die Erstellungsoption der Funktion move_defect auf True gesetzt ist, werden die Generierung und die nachfolgende Verschiebung ausgeführt. Wenn False (Standard), verschieben Sie nur (vorausgesetzt, es wurde bereits generiert), ohne es zu generieren. Wie wir später sehen werden, wird die Messung nach dem Verschieben durchgeführt, wenn Sie True für die Option "Vernichten" angeben (vorausgesetzt, die Fehlerpaare sind benachbart). Weitere Informationen zur Funktion make_defect finden Sie in der Funktionsdefinition. Dies gibt Ihnen ein logisches $ \ ket {+} $. Das letzte if lq [0] == '-' ist eine Operation, die durch Anwenden des logischen $ Z $ -Operators invertiert werden muss, wenn der 0. Eingabestatus für die Funktion oper_logical_cnot'- 'ist. Weitere Informationen zur Funktion operator_logical_Z finden Sie auch in der Funktionsdefinition.

# set logical qubit #1
d1_pos_A, d1_pos_B = [2,5], [3,5]
d1_path = [[3,5],[4,5],[5,5]]
move_defect(sb, d1_pos_A, d1_pos_B, d1_path, 'd', lattice, create=True)

# set logical qubit #2
p2_pos_A, p2_pos_B = [0,7], [1,7]
p2_path = [[1,7],[2,7],[3,7]]
move_defect(sb, p2_pos_A, p2_pos_B, p2_path, 'p', lattice, create=True)

# set logical qubit #3
p3_pos_A, p3_pos_B = [6,0], [6,1]
p3_path = [[6,1],[6,2]]
move_defect(sb, p3_pos_A, p3_pos_B, p3_path, 'p', lattice, create=True)
if lq[1] == '-': operate_logical_Z(sb, 3, lattice)

damit. Erzeugt das erste, zweite und dritte logische Quantenbit. Damit ist der Ausgangszustand abgeschlossen.

# braid logical qubit #0
p0_pos_A, p0_pos_B = [0,0], [0,2]
p0_path = [[0,2],[1,2],[2,2],[3,2],[3,3],[3,4],[3,5],[3,6],
           [2,6],[1,6],[0,6],[0,5],[0,4],[0,3],[0,2]]
move_defect(sb, p0_pos_A, p0_pos_B, p0_path, 'p', lattice)

Dann wird das 0. logische Quantenbit (p-Typ-Defekt) um das 1. logische Quantenbit (d-Typ-Defekt) gewickelt.

# braid logical qubit #2
p2_pos_A, p2_pos_B = [0,7], [3,7]
p2_path = [[3,7],[3,6],[3,5],[3,4],[3,3],[4,3],[5,3],
          [6,3],[6,4],[6,5],[6,6],[6,7],[5,7],[4,7],[3,7]]
move_defect(sb, p2_pos_A, p2_pos_B, p2_path, 'p', lattice)

Wickeln Sie dann das zweite logische Quantenbit (p-Typ-Defekt) um das erste logische Quantenbit (d-Typ-Defekt).

# braid and annihilate logical qubit #3
p3_pos_A, p3_pos_B = [6,0], [6,2]
p3_path = [[6,2],[6,3],[6,4],[6,5],[6,6],[5,6],[4,6],[3,6],
           [3,5],[3,4],[3,3],[3,2],[4,2],[5,2],[6,2],[6,1]]
mval_p = move_defect(sb, p3_pos_A, p3_pos_B, p3_path, 'p', lattice, annihilate=True)

Dann wird das dritte logische Quantenbit (p-Typ-Defekt) um das erste logische Quantenbit (d-Typ-Defekt) gewickelt und verschwindet schließlich. Da die Funktion move_defect so ausgelegt ist, dass sie den gemessenen Wert zum Zeitpunkt des Aussterbens zurückgibt, behalten Sie ihn als mval_p bei (wird später verwendet).

# braid and annihilate logical qubit #1
d1_pos_A, d1_pos_B = [2,5], [5,5]
d1_path = [[5,5],[4,5],[3,5]]
mval_d = move_defect(sb, d1_pos_A, d1_pos_B, d1_path, 'd', lattice, annihilate=True)

Misst das erste logische Quantenbit (d-Typ-Defekt). Der gemessene Wert sei mval_d.

if mval_p == '1':
    operate_logical_Z(sb, 0, lattice)
    operate_logical_Z(sb, 2, lattice)

Wenn also der Wert von mval_p (gemessener Wert zum Zeitpunkt des Erlöschens des 3. logischen Quantenbits) -1 (1 als Messindex) ist, werden das letzte 0. und 2. logische Quantenbit invertiert. Ich werde.

# measure logical qubits: #0 and #2
chain_0 = get_chain(get_path([0,0],[0,2]), 'p', lattice)
chain_2 = get_chain(get_path([0,7],[3,7]), 'p', lattice)
freq = measure_logical_X(sb, chain_0, chain_2, shots=shots)
print("Input('{0:}') == [CNOT] ==> {1:}".format(lq, freq))

Um zu überprüfen, ob es sich um eine CNOT-Operation handelt, messen Sie das 0. logische Quantenbit und das 2. logische Quantenbit für $ X $. Da es sich bei beiden um Fehler vom Typ p handelt, können Sie die Kette von $ X $ -Operatoren messen, die die Fehler verbinden. Ich mache das mit dem Operator Measure_logical_X. Das Messergebnis wird in Freq im Zählerformat gespeichert und am Ende angezeigt. das ist alles.

Ergebnis

Das Ausführungsergebnis ist wie folgt.

Input('++') == [CNOT] ==> Counter({'++': 10})
Input('+-') == [CNOT] ==> Counter({'--': 10})
Input('-+') == [CNOT] ==> Counter({'-+': 10})
Input('--') == [CNOT] ==> Counter({'+-': 10})

Für alle vier Eingabemuster bestand eine 100% ige Chance, die richtigen CNOT-Operationsergebnisse zu erhalten.

abschließend

Es ist sehr interessant, logische Operationen mit Braiding wie diesem ausführen zu können, aber es ist ziemlich schwierig, es auf der tatsächlichen Hardware zu implementieren. Es gibt viele Fehler in der Gitterebene, und wir müssen die Berechnung durchführen, um sie zu wickeln, aber die anfängliche Anordnung und die Wicklungsmethode sind nicht die gleichen, und erstens ist es vor vielen Fehlern nicht gut. Wenn implementiert, kann sich das Programm "Circuit =" im Spaghetti-Zustand befinden (oder vielmehr könnten logische Operationen ausgeführt werden, indem es in den Spaghetti-Zustand versetzt wird, hmm). Vielleicht ist dies die Rolle des Compilers, so dass sich die breite Öffentlichkeit vielleicht nicht darum kümmert, aber es ist ein großes Problem für diejenigen, die von nun an einen Compiler erstellen werden. Immerhin ist die Gitterchirurgie sauberer und sieht besser aus als das Flechten (obwohl ich noch nicht studiert habe).

Als ich beim Schreiben des Entwurfs dieses Artikels darüber nachdachte, machte ich die folgende Ankündigung.

Es scheint, dass die Schaltungskomprimierung effizient durchgeführt werden kann, indem ein sogenannter ZX-Kalkül verwendet wird, der auf Flechten anstelle von Gitterchirurgie basiert (wie). Möglicherweise müssen Sie es überprüfen! (Aber was ist vorher zu tun ...)

das ist alles

Recommended Posts

Grundlagen der Quanteninformationstheorie: Universelle Quantenberechnung durch Oberflächencode (1)
Grundlagen der Quanteninformationstheorie: Topologische Oberflächencodes
Grundlagen der Quanteninformationstheorie: Logische Operation durch Oberflächencode (Brading)
Grundlagen der Quanteninformationstheorie: Quantenfehlerkorrektur (CSS-Code)
Grundlagen der Quanteninformationstheorie: Quantenfehlerkorrektur (Stabilisatorcode: 4)
Grundlagen der Quanteninformationstheorie: Entropie (2)
Grundlagen der Quanteninformationstheorie: Quantenfehlerkorrektur (klassischer linearer Code)
Grundlagen der Quanteninformationstheorie: Horebaud-Grenzen
Grundlagen der Quanteninformationstheorie: Spurenentfernung
Grundlagen der Quanteninformationstheorie: Quantenzustands-Tomographie
Grundlagen der Quanteninformationstheorie: Datenkomprimierung (2)
Grundlagen der Quanteninformationstheorie: Fehlertolerante Quantenberechnung
Berechnung der Ähnlichkeit durch MinHash
Quantifizierung des "Bewusstseins" in der integrierten Informationstheorie (IIT3.0), Berechnungsmethode von Φ
Lesen Sie "Grundlagen des Quantenglühens", Tag 5
Lesen Sie "Grundlagen des Quantenglühens", Tag 6
Beispiel für das Umschreiben von Code durch ast.NodeTransformer
Grundlagen der Tableau-Grundlagen (Visualisierung mit geografischen Informationen)