Przejdź do głównej treści

Toric code

Teraz omówimy konkretny CSS code znany jako toric code, odkryty przez Aleksieja Kitajewa w 1997 roku. W rzeczywistości toric code to nie jeden kod, lecz rodzina kodów — po jednym dla każdej dodatniej liczby całkowitej począwszy od 2. Kody te mają kilka kluczowych właściwości:

  • Generatory Stabilizer mają niską wagę, a w szczególności wszystkie mają wagę 4. W nomenklaturze teorii kodowania toric code jest przykładem kwantowego kodu kontroli parzystości o niskiej gęstości, czyli kwantowego kodu LDPC (gdzie niska oznacza w tym przypadku 4). Jest to wygodne, ponieważ każdy pomiar generatora Stabilizer nie musi angażować zbyt wielu qubitów.

  • Toric code ma geometryczną lokalność. Oznacza to, że generatory Stabilizer nie tylko mają niską wagę, ale można też rozmieścić kubity przestrzennie tak, by każdy pomiar generatora Stabilizer angażował wyłącznie kubity leżące blisko siebie. W zasadzie sprawia to, że takie pomiary są łatwiejsze do wykonania niż gdyby dotyczyły qubitów oddalonych przestrzennie.

  • Kolejne elementy rodziny toric code mają coraz większy dystans i mogą tolerować stosunkowo wysoką stopę błędów.

Opis toric code

Niech L2L\geq 2 będzie dodatnią liczbą całkowitą i rozważmy lattice L×LL\times L z tzw. periodycznymi brzegami. Na przykład poniższy rysunek przedstawia lattice L×LL\times L dla L=9.L=9.

Lattice 9 na 9 z periodycznymi brzegami

Zwróć uwagę, że linie po prawej stronie i na dole są liniami przerywanymi. Wskazuje to, że przerywana linia po prawej jest tą samą linią co linia po lewej stronie, i analogicznie przerywana linia na dole jest tą samą linią co linia na samej górze.

Fizyczna realizacja takiej konfiguracji wymaga trzech wymiarów. Możemy na przykład uformować lattice w cylinder, dopasowując najpierw lewą i prawą krawędź, a następnie wygiąć cylinder tak, by okręgi na końcach — które były górną i dolną krawędzią lattice — spotkały się. Możemy też najpierw dopasować górę i dół, a potem boki; działa to w obie strony i dla celów tego omówienia nie ma znaczenia, którą kolejność wybierzemy.

Otrzymujemy w ten sposób torus — czyli, innymi słowy, pączek (choć może lepszym obrazem jest dętka, bo to nie jest bryła: lattice staje się jedynie powierzchnią torusa). Stąd pochodzi nazwa „toric code".

Lattice 9 na 9 zwinięta w torus

Sposób, w jaki można „poruszać się" po takim torusie między sąsiednimi punktami lattice, będzie prawdopodobnie znajomy osobom, które grały w stare gry wideo, gdzie wyjście poza górną krawędź ekranu powodowało pojawienie się na dole, i podobnie po lewej i prawej stronie. Właśnie tak będziemy patrzeć na tę lattice z periodycznymi brzegami, bez odnoszenia się wprost do torusa w trójwymiarowej przestrzeni.

Następnie kubity rozmieszczamy na krawędziach tej lattice, jak pokazuje poniższy rysunek, gdzie kubity oznaczono wypełnionymi niebieskimi kółkami.

Kubity na krawędziach periodycznej lattice 9 na 9

Zwróć uwagę, że kubity umieszczone na liniach przerywanych nie są wypełnione, bo są już reprezentowane na najwyższej i skrajnie lewej linii lattice. Łącznie jest 2L22L^2 qubitów: L2L^2 qubitów na poziomych liniach i L2L^2 qubitów na pionowych liniach.

Aby opisać sam toric code, pozostaje opisać generatory Stabilizer:

  • Dla każdej płytki (plaquette) utworzonej przez linie w lattice istnieje jeden generator Stabilizer ZZ, uzyskany przez tensoring macierzy ZZ na czterech qubitach stykających się z tą płytką oraz macierzy identyczności na wszystkich pozostałych qubitach.

  • Dla każdego vertex (wierzchołka) utworzonego przez linie w lattice istnieje jeden generator Stabilizer XX, uzyskany przez tensoring macierzy XX na czterech qubitach sąsiadujących z tym vertex oraz macierzy identyczności na wszystkich pozostałych qubitach.

W obu przypadkach otrzymujemy operację Pauli o wadze 4. Poszczególne generatory Stabilizer możemy zilustrować następująco.

Typy generatorów Stabilizer dla toric code

Poniżej znajduje się ilustracja przedstawiająca kilka przykładów generatorów Stabilizer w kontekście samej lattice. Zwróć uwagę, że uwzględniono generatory Stabilizer owijające się wokół periodycznych brzegów. Takie generatory nie są wyjątkowe ani w żaden sposób wyróżnione spośród tych, które się nie owijają.

Przykłady generatorów Stabilizer na lattice

Aby kod był poprawnym kodem Stabilizer, generatory Stabilizer muszą komutować. Jak zwykle, wszystkie generatory Stabilizer ZZ komutują ze sobą nawzajem, ponieważ ZZ komutuje samo ze sobą, a identyczność komutuje ze wszystkim — i analogicznie dla generatorów Stabilizer XX. Generatory Stabilizer ZZ i XX wyraźnie komutują, gdy działają nietrywialnie na rozłącznych zbiorach qubitów, jak w przykładach z poprzedniego rysunku. Pozostała możliwość to sytuacja, gdy generator Stabilizer ZZ i generator Stabilizer XX nakładają się na qubitach, na których działają nietrywialnie — gdy tak się zdarza, generatory zawsze nakładają się na dokładnie dwóch qubitach, jak na kolejnym rysunku.

Nakładające się generatory Stabilizer dla toric code

W konsekwencji dwa takie generatory Stabilizer komutują, tak jak komutują ZZZ\otimes Z i XXX\otimes X. Wszystkie generatory Stabilizer komutują więc ze sobą nawzajem.

Drugi wymagany warunek dla generatorów Stabilizer kodu Stabilizer to to, że tworzą one minimalny zbiór generujący. Ten warunek w rzeczywistości nie jest spełniony przez ten zbiór: jeśli pomnożymy wszystkie generatory Stabilizer ZZ razem, otrzymamy operację identyczności, i podobnie dla generatorów Stabilizer XX. Zatem każdy z generatorów Stabilizer ZZ można wyrazić jako iloczyn wszystkich pozostałych, i analogicznie każdy z generatorów Stabilizer XX można wyrazić jako iloczyn pozostałych generatorów Stabilizer XX. Jeśli jednak usuniemy po jednym generatorze Stabilizer każdego typu, uzyskamy minimalny zbiór generujący.

Dla jasności: w praktyce zależy nam w równym stopniu na wszystkich generatorach Stabilizer i w ściśle operacyjnym sensie nie ma potrzeby wybierania jednego generatora Stabilizer każdego typu do usunięcia. Jednak na potrzeby analizy kodu — a w szczególności zliczania generatorów — możemy wyobrazić sobie, że jeden generator Stabilizer każdego typu został usunięty, uzyskując minimalny zbiór generujący, mając na uwadze, że wyniki tych usuniętych generatorów (traktowanych jako obserwable) zawsze możemy wywnioskować z wyników wszystkich pozostałych obserwabli generatorów Stabilizer tego samego typu.

Pozostaje L21L^2 - 1 generatorów Stabilizer każdego typu, czyli łącznie 2L222L^2 - 2 w (hipotetycznym) minimalnym zbiorze generującym. Biorąc pod uwagę, że łączna liczba qubitów wynosi 2L22L^2, toric code koduje 2L22(L21)=22L^2 - 2(L^2 - 1) = 2 kubity.

Ostatni wymagany warunek dla generatorów Stabilizer to istnienie co najmniej jednego wektora stanu kwantowego unieruchomionego przez wszystkie generatory Stabilizer. Przekonamy się, że tak jest, kontynuując analizę kodu — można też uzasadnić, że nie ma możliwości wygenerowania 1-1 razy identyczności na wszystkich 2L22L^2 qubitach z tych generatorów Stabilizer.

Wykrywanie błędów

Kod toryczny ma prostą i elegancką definicję, jednak jego właściwości korekcji błędów kwantowych mogą nie być od razu oczywiste. Jak się okazuje, to naprawdę niesamowity kod! Żeby zrozumieć, dlaczego i jak działa, zacznijmy od przyjrzenia się różnym błędom i generowanym przez nie syndrome'om.

Kod toryczny jest kodem CSS, ponieważ wszystkie nasze generatory Stabilizer są albo generatorami Stabilizer ZZ, albo generatorami Stabilizer XX. Oznacza to, że błędy XX i błędy ZZ można wykrywać (i ewentualnie korygować) niezależnie. W rzeczywistości między generatorami Stabilizer ZZ i XX istnieje prosta symetria, która pozwala nam analizować błędy XX i błędy ZZ w zasadniczo ten sam sposób. Skupimy się więc na błędach XX, które są potencjalnie wykrywane przez generatory Stabilizer ZZ — ale całą poniższą dyskusję można bezpośrednio przenieść z błędów XX na błędy ZZ, które analogicznie są wykrywane przez generatory Stabilizer XX.

Poniższy diagram przedstawia efekt błędu XX na jednym qubicie. Zakładamy, że nasze 2L22L^2 kubitów znajdowało się wcześniej w stanie należącym do przestrzeni kodowej kodu torycznego, co powoduje, że wszystkie pomiary generatorów Stabilizer dają wynik +1.+1. Generatory Stabilizer ZZ wykrywają błędy XX, a każdemu kafeltowi na rysunku odpowiada jeden taki generator Stabilizer — wynik pomiaru odpowiedniego generatora Stabilizer możemy więc zaznaczyć kolorem tego kafla: wyniki +1+1 oznaczone są białymi kafelkami, a wyniki 1-1 — szarymi kafelkami. Jeśli na jednym z kubitów wystąpi błąd bit-flip, efektem jest to, że pomiary generatorów Stabilizer odpowiadających dwóm kafelkom stykającym się z dotkniętym kubitem zaczynają dawać wynik 1.-1.

Efekt pojedynczego błędu bit-flip w kodzie torycznym

Jest to intuicyjne, gdy rozważymy generatory Stabilizer ZZ i ich zachowanie. W istocie każdy generator Stabilizer ZZ mierzy parzystość czterech kubitów stykających się z odpowiednim kafelkiem (względem bazy standardowej). Wynik +1+1 nie oznacza więc, że na tych czterech kubitach nie wystąpiły żadne błędy XX — wskazuje jedynie, że na tych kubitach wystąpiła parzysta liczba błędów XX, natomiast wynik 1-1 oznacza, że wystąpiła nieparzysta liczba błędów XX. Pojedynczy błąd XX odwraca zatem parzystość czterech bitów na obu stykających się z nim kafelkach, powodując, że pomiary generatorów Stabilizer dają wynik 1.-1.

Teraz wprowadźmy wiele błędów XX, żeby zobaczyć, co się stanie. Rozważymy w szczególności łańcuch sąsiadujących błędów XX, gdzie dwa błędy XX są sąsiadujące, jeśli dotyczą kubitów stykających się z tym samym kafelkiem.

Efekt łańcucha błędów bit-flip w kodzie torycznym

Dwa generatory Stabilizer ZZ na końcach łańcucha dają w tym przypadku wynik 1-1, ponieważ na dwóch odpowiadających im kafelkach wystąpiła nieparzysta liczba błędów XX. Wszystkie pozostałe generatory Stabilizer ZZ dają natomiast wynik +1+1 — w tym te stykające się z łańcuchem, lecz nie będące jego końcami — ponieważ na kubitach stykających się z odpowiadającymi im kafelkami wystąpiła parzysta liczba błędów XX.

Tak więc, dopóki mamy łańcuch błędów XX z końcami, kod toryczny wykryje, że wystąpiły błędy, co objawi się wynikami 1-1 w pomiarach generatorów Stabilizer ZZ odpowiadających końcom łańcucha. Zwróć uwagę, że rzeczywisty łańcuch błędów nie jest ujawniany — widoczne są tylko końce! To nie problem — w następnym podrozdziale zobaczymy, że nie musimy wiedzieć dokładnie, które kubity zostały dotknięte błędami XX, żeby je skorygować. (Kod toryczny jest przykładem wysoce zdegenerowanego kodu w tym sensie, że na ogół nie identyfikuje jednoznacznie korygowanych błędów.)

Możliwe jest jednak, że łańcuch sąsiadujących błędów XX nie ma końców — tzn. łańcuch błędów może tworzyć zamkniętą pętlę, jak na poniższym rysunku.

Zamknięta pętla błędów bit-flip w kodzie torycznym

W takim przypadku na każdym kafelku wystąpiła parzysta liczba błędów XX, więc każdy pomiar generatora Stabilizer daje wynik +1+1. Zamknięte pętle sąsiadujących błędów XX nie są więc wykrywane przez kod.

Mogłoby się to wydawać rozczarowujące, bo do utworzenia zamkniętej pętli wystarczą zaledwie cztery błędy XX (a liczymy na coś znacznie lepszego niż kod o odległości 4). Jednak zamknięta pętla błędów XX w postaci pokazanej na poprzednim rysunku nie jest w rzeczywistości błędem — bo jest ona elementem Stabilizer! Przypomnij sobie, że oprócz generatorów Stabilizer ZZ mamy też generator Stabilizer XX dla każdego vertex w kratowinach. A mnożąc sąsiadujące generatory Stabilizer XX, uzyskujemy zamknięte pętle operacji XX. Na przykład zamkniętą pętlę z poprzedniego rysunku można uzyskać, mnożąc generatory Stabilizer XX wskazane na poniższym rysunku.

Zamknięta pętla błędów bit-flip wygenerowana przez generatory Stabilizer X

To jednak nie jedyny typ zamkniętej pętli błędów XX, jaki możemy mieć — i nie jest tak, że każda zamknięta pętla błędów XX należy do Stabilizer. W szczególności różne typy pętli można scharakteryzować następująco.

  1. Zamknięte pętle błędów XX z parzystą liczbą błędów XX na każdej poziomej linii i każdej pionowej linii kubitów. (Powyższy przykład należy do tej kategorii.) Pętle tej postaci są zawsze zawarte w Stabilizer, ponieważ można je efektywnie skurczyć do zera przez mnożenie przez generatory Stabilizer XX.

  2. Zamknięte pętle błędów XX z nieparzystą liczbą błędów XX na co najmniej jednej poziomej lub co najmniej jednej pionowej linii kubitów. Pętle tej postaci nigdy nie są zawarte w Stabilizer i dlatego reprezentują nietrywialny błędy niezauważane przez kod.

Przykład zamkniętej pętli błędów XX należącej do drugiej kategorii pokazano na poniższym diagramie.

Zamknięta pętla błędów bit-flip nienależąca do Stabilizer

Taki łańcuch błędów nie jest zawarty w Stabilizer, ponieważ każdy generator Stabilizer XX umieszcza parzystą liczbę operacji XX na każdej poziomej linii i każdej pionowej linii kubitów. Jest to więc rzeczywisty przykład nietrywialnego błędu, którego kod nie wykrywa.

Kluczem jest to, że jedynym sposobem na utworzenie pętli drugiego rodzaju jest okrążenie torusa — albo dookoła dziury pośrodku torusa, albo przez nią, albo w obu kierunkach. Intuicyjnie mówiąc, łańcucha błędów XX takiego jak ten nie można skurczyć do zera przez mnożenie przez generatory Stabilizer XX, ponieważ topologia torusa na to nie pozwala. Z tego powodu kod toryczny jest czasami klasyfikowany jako topologiczny kwantowy kod korekcji błędów. Minimalna długość takiej pętli to LL, i właśnie taka jest odległość kodu torycznego: każda zamknięta pętla błędów XX o długości mniejszej niż LL musi należeć do pierwszej kategorii, a więc jest zawarta w Stabilizer; natomiast każdy łańcuch błędów XX z końcami jest wykrywany przez kod.

Ponieważ kod toryczny używa 2L22L^2 kubitów do zakodowania 22 kubitów i ma odległość LL, jest to kod Stabilizer [[2L2,2,L]][[2L^2,2,L]].

Korekcja błędów

Omówiliśmy wykrywanie błędów w kodzie torycznym, a teraz krótko porozmawiamy o tym, jak korygować błędy. Kod toryczny jest kodem CSS, więc błędy XX i ZZ można wykrywać i korygować niezależnie. Skupiając się nadal na generatorach Stabilizer ZZ, które wykrywają błędy XX, rozważmy, jak można skorygować łańcuch błędów XX. (Błędy ZZ koryguje się w symetryczny sposób.)

Jeśli podczas pomiaru generatorów Stabilizer ZZ pojawi się syndrome różny od syndrome (+1,,+1)(+1,\ldots,+1), wyniki 1-1 ujawniają końce jednego lub więcej łańcuchów błędów XX. Możemy spróbować skorygować te błędy, parując wyniki 1-1 i tworząc łańcuch korekcji XX między nimi. Przy tym sensownie jest wybierać najkrótsze ścieżki, wzdłuż których wykonywane są korekty.

Rozważmy na przykład poniższy diagram, który przedstawia syndrome z dwoma wynikami 1-1 oznaczonymi szarymi kafelkami, spowodowany łańcuchem błędów XX zilustrowanym magentową linią i kółkami. Jak już zauważyliśmy, sam łańcuch nie jest ujawniany przez syndrome — widoczne są tylko jego końce.

Korekcja błędów X za pomocą najkrótszej ścieżki

Żeby spróbować skorygować ten łańcuch błędów, wybieramy najkrótszą ścieżkę między wynikami pomiaru 1-1 i stosujemy bramki XX jako korekty do kubitów wzdłuż tej ścieżki (zaznaczonych na żółto na rysunku). Choć korekty mogą nie odpowiadać dokładnie rzeczywistemu łańcuchowi błędów, błędy i korekty razem tworzą zamkniętą pętlę operacji XX zawartą w Stabilizer kodu. Korekta jest więc w tej sytuacji skuteczna, ponieważ łączny efekt błędów i korekcji to brak jakiegokolwiek działania na zakodowanym stanie.

Ta strategia nie zawsze będzie skuteczna. Na przykład inne wytłumaczenie tego samego syndrome co na poprzednim rysunku pokazano na poniższym rysunku.

Dopełnienie błędu logicznego przez korekcje

Tym razem ten sam łańcuch korekcji co poprzednio nie koryguje tego łańcucha błędów, ponieważ łączny efekt błędów i korekcji to zamknięta pętla operacji XX owijająca się wokół torusa, która ma nietrywialny wpływ na przestrzeń kodową. Nie ma więc gwarancji, że opisana strategia wybierania najkrótszej ścieżki korekcji XX między dwoma wynikami pomiaru syndrome 1-1 prawidłowo skoryguje błąd, który wywołał ten syndrome.

Być może bardziej prawdopodobne, w zależności od modelu szumu, jest zmierzenie syndrome z więcej niż dwoma wpisami 1-1, jak sugeruje poniższy rysunek.

Wiele łańcuchów korekcji

W takim przypadku znane są różne strategie korekcji. Jedną naturalną strategią jest próba parowania wyników pomiaru 1-1 i wykonywanie korekcji wzdłuż najkrótszych ścieżek łączących pary, co wskazano na rysunku kolorem żółtym. W szczególności można obliczyć minimalne doskonałe dopasowanie wagowe między wynikami pomiaru 1-1, a następnie połączyć pary najkrótszymi ścieżkami korekcji XX. Obliczenie minimalnego doskonałego dopasowania wagowego można wykonać efektywnie klasycznym algorytmem zwanym algorytmem blossom, odkrytym przez Edmondsa w latach 60. XX wieku.

To podejście na ogół nie jest optymalne dla najczęściej badanych modeli szumu, ale na podstawie symulacji numerycznych działa bardzo dobrze w praktyce poniżej wskaźnika szumu wynoszącego około 10%, przy założeniu niezależnych błędów Pauli, gdzie X,X, YY i ZZ są jednakowo prawdopodobne.